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