diff --git a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntEnterpriseInformationController.java b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntEnterpriseInformationController.java index d0170aaf..0d6759a4 100644 --- a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntEnterpriseInformationController.java +++ b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntEnterpriseInformationController.java @@ -96,4 +96,41 @@ public class AppEntEnterpriseInformationController { return R.ok(result); } + /** + * 根据企业纳税识别号强制生成二维码 + *

+ * 忽略历史记录检查,直接将旧二维码置为失效并生成新的二维码, + * 返回新二维码URL、企业名称、生成时间 + *

+ * + * @param enterpriseNumber 企业纳税识别号 + * @return 二维码信息(qrCodeUrl, enterpriseName, generateTime) + */ + @SaIgnore + @GetMapping("/forceGenerateQrCode/{enterpriseNumber}") + public R> forceGenerateQrCode(@PathVariable String enterpriseNumber) { + if (enterpriseNumber == null || enterpriseNumber.trim().isEmpty()) { + return R.fail("企业纳税识别号不能为空"); + } + + // 1. 强制生成二维码(跳过历史记录检查) + QrCodeGenerateHistoryVo qrCodeVo = enterpriseInformationService.forceGenerateQrCode( + "", enterpriseNumber, "app.enterprise", "强制重新生成二维码"); + + // 2. 查询企业名称 + String enterpriseName = ""; + EnterpriseInformationVo enterpriseInfo = enterpriseInformationService.queryByEnterpriseNumber(enterpriseNumber); + if (enterpriseInfo != null) { + enterpriseName = enterpriseInfo.getEnterpriseName(); + } + + // 3. 构建返回数据 + Map result = new HashMap<>(); + result.put("qrCodeUrl", qrCodeVo.getQrCodeUrl()); + result.put("enterpriseName", enterpriseName); + result.put("generateTime", qrCodeVo.getGenerateTime()); + + return R.ok(result); + } + } diff --git a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntTestEnfDemoController.java b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntTestEnfDemoController.java index 481ab28c..8fce43af 100644 --- a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntTestEnfDemoController.java +++ b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntTestEnfDemoController.java @@ -30,7 +30,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; @Validated @RequiredArgsConstructor @RestController -@RequestMapping("/app-ent/enfDemo") +@RequestMapping("/app-ent/enfdemo") public class AppEntTestEnfDemoController extends BaseController { private final ITestEnfDemoService testEnfDemoService; diff --git a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseInformationService.java b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseInformationService.java index c0aad8d6..fd6b3b3e 100644 --- a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseInformationService.java +++ b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseInformationService.java @@ -86,4 +86,16 @@ public interface IEnterpriseInformationService { * @return 二维码生成历史记录 */ QrCodeGenerateHistoryVo generateQrCode(String type, String enterpriseNumber, String formModule,String reasonsChange); + + /** + * 强制为企业生成蓝色二维码(含 LOGO) + *

忽略历史记录检查,直接生成新的二维码,旧二维码将被置为失效

+ * + * @param type 二维码类型 + * @param enterpriseNumber 企业纳税识别号 + * @param formModule 表单模块 + * @param reasonsChange 变更原因 + * @return 二维码生成历史记录 + */ + QrCodeGenerateHistoryVo forceGenerateQrCode(String type, String enterpriseNumber, String formModule, String reasonsChange); } diff --git a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseInformationServiceImpl.java b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseInformationServiceImpl.java index 33689072..d4781bd1 100644 --- a/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseInformationServiceImpl.java +++ b/ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseInformationServiceImpl.java @@ -2,6 +2,7 @@ package com.zdxt.enforcementcode.service.impl; import com.zdxt.enforcementcode.domain.EnterpriseInformation; import com.zdxt.enforcementcode.domain.bo.EnterpriseInformationBo; +import com.zdxt.enforcementcode.domain.bo.QrCodeGenerateHistoryBo; import com.zdxt.enforcementcode.domain.vo.EnterpriseInformationVo; import com.zdxt.enforcementcode.domain.vo.QrCodeGenerateHistoryVo; import com.zdxt.enforcementcode.mapper.EnterpriseInformationMapper; @@ -209,4 +210,42 @@ public class EnterpriseInformationServiceImpl implements IEnterpriseInformationS return qrCodeVo; } + + /** + * 强制为企业生成蓝色二维码(含 LOGO) + *

忽略历史记录检查,直接将旧二维码置为失效并生成新的二维码

+ */ + @Override + public QrCodeGenerateHistoryVo forceGenerateQrCode(String type, String enterpriseNumber, String formModule, String reasonsChange) { + // 1. 校验企业是否存在 + EnterpriseInformationVo enterprise = queryByEnterpriseNumber(enterpriseNumber); + if (enterprise == null) { + throw new ServiceException("企业纳税识别号[" + enterpriseNumber + "]对应的企业不存在"); + } + + // 2. 将旧的有效二维码置为失效 + QrCodeGenerateHistoryVo existingQrCode = qrCodeGenerateHistoryService.queryLatestByEnterpriseNumber(enterpriseNumber); + if (existingQrCode != null) { + QrCodeGenerateHistoryBo invalidBo = new QrCodeGenerateHistoryBo(); + invalidBo.setId(existingQrCode.getId()); + invalidBo.setStatus(1L); // 1=失效 + invalidBo.setReasonsChange("强制重新生成二维码"); + qrCodeGenerateHistoryService.updateByBo(invalidBo); + log.info("企业[{}]旧二维码已置为失效,qrCodeId={}", enterpriseNumber, existingQrCode.getId()); + } + + // 3. 生成新二维码 + QrCodeGenerateHistoryVo qrCodeVo = QrCodeHelper.generateBlueWithLogoAndSave(enterprise.getSalt(), + type, enterprise.getId(), enterpriseNumber, formModule, new Date(), "", reasonsChange); + log.info("企业[{}]二维码强制生成成功,qrCodeId={}", enterpriseNumber, qrCodeVo.getId()); + + // 4. 更新企业的二维码ID和最后生成时间 + EnterpriseInformationBo updateBo = new EnterpriseInformationBo(); + updateBo.setId(enterprise.getId()); + updateBo.setQrCodeId(qrCodeVo.getId()); + updateBo.setLastQrCodeTime(qrCodeVo.getGenerateTime()); + updateByBo(updateBo); + + return qrCodeVo; + } } diff --git a/zdxt-web-client/zdxt-enforcement-code-app/src/api/demo/index.js b/zdxt-web-client/zdxt-enforcement-code-app/src/api/demo/index.js index 25015a67..357eb292 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/src/api/demo/index.js +++ b/zdxt-web-client/zdxt-enforcement-code-app/src/api/demo/index.js @@ -1,6 +1,6 @@ import { _get, _post, _delete } from "../../http/index"; -let baseUrl = "/app/enterprise/enfDemo"; +let baseUrl = "/app-ent/enfdemo"; // 查询enf测试单列表(分页) export const getEnfDemoList = (params, success, error) => _get(baseUrl + "/list", params, success, error); diff --git a/zdxt-web-client/zdxt-enforcement-code-app/src/config/env.js b/zdxt-web-client/zdxt-enforcement-code-app/src/config/env.js new file mode 100644 index 00000000..f4deca6f --- /dev/null +++ b/zdxt-web-client/zdxt-enforcement-code-app/src/config/env.js @@ -0,0 +1,6 @@ +let baseUrl = import.meta.env.VITE_BASE_URL || "未定义"; +let appEnv = import.meta.env.VITE_APP_ENV || "未定义"; +export { + baseUrl, + appEnv, +} diff --git a/zdxt-web-client/zdxt-enforcement-code-app/src/http/http.js b/zdxt-web-client/zdxt-enforcement-code-app/src/http/http.js index 85543270..63eec60e 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/src/http/http.js +++ b/zdxt-web-client/zdxt-enforcement-code-app/src/http/http.js @@ -1,10 +1,12 @@ import axios from 'axios'; +import { baseUrl } from "../config/env"; import { $globalStore } from "../common/globalStore" import { $globalRouter } from "../common/globalRouter" // import {cache} from '@/store/store'; // axios.defaults.withCredentials = true //const source = axios.CancelToken.source() const http = axios.create({ + baseURL: baseUrl, traditional: true, contentType : "application/json", timeout: 1000 * 500000, // 1 秒 diff --git a/zdxt-web-client/zdxt-enforcement-code-app/src/http/index.js b/zdxt-web-client/zdxt-enforcement-code-app/src/http/index.js index 8dabb361..1113b3f2 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/src/http/index.js +++ b/zdxt-web-client/zdxt-enforcement-code-app/src/http/index.js @@ -33,10 +33,7 @@ const isHttpLink = (url) =>{ } function request(type, url, params, success, error) { - var targetUrl = ""; - if(isHttpLink(url)){ - targetUrl = url - } + var targetUrl = url; let config = { method: type, url: targetUrl, diff --git a/zdxt-web-client/zdxt-enforcement-code-app/src/views/enforcement/scanEntQRCode.vue b/zdxt-web-client/zdxt-enforcement-code-app/src/views/enforcement/scanEntQRCode.vue new file mode 100644 index 00000000..562470d1 --- /dev/null +++ b/zdxt-web-client/zdxt-enforcement-code-app/src/views/enforcement/scanEntQRCode.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-dev b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-dev index 17b985fa..cbf10258 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-dev +++ b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-dev @@ -2,3 +2,4 @@ VITE_PORT = 12002 VITE_BASE_URL = 'http://localhost:17000/enf-ep' VITE_DEFAULT_LOGIN = '/enforcement/login' +VITE_APP_ENV = 'dev' diff --git a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-prod b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-prod index 0f23a325..ff4cbce9 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-prod +++ b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enforcement-prod @@ -1,4 +1,5 @@ -# 执法端开发环境 +# 执法端生产环境 VITE_PORT = 12002 VITE_BASE_URL = 'http://localhost:17000/enf-ep' VITE_DEFAULT_LOGIN = '/enforce/login' +VITE_APP_ENV = 'prod' diff --git a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-dev b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-dev index 4b03e4de..8328733c 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-dev +++ b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-dev @@ -2,3 +2,4 @@ VITE_PORT = 12001 VITE_BASE_URL = '/api/ent-ep' VITE_DEFAULT_LOGIN = '/enterprise/login' +VITE_APP_ENV = 'dev' diff --git a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-prod b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-prod index 6a798a06..2c967aae 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-prod +++ b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.enterprise-prod @@ -1,4 +1,5 @@ -# 企业端开发环境 +# 企业端生产环境 VITE_PORT = 12001 VITE_BASE_URL = 'http://localhost:17000/ent-ep' VITE_DEFAULT_LOGIN = '/enterprise/login' +VITE_APP_ENV = 'prod' diff --git a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-dev b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-dev index c51a581f..87f1b7f2 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-dev +++ b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-dev @@ -2,3 +2,4 @@ VITE_PORT = 12003 VITE_BASE_URL = 'http://localhost:17000/sup-ep' VITE_DEFAULT_LOGIN = '/supervision/login' +VITE_APP_ENV = 'dev' diff --git a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-prod b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-prod index e69de29b..2ee605bd 100644 --- a/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-prod +++ b/zdxt-web-client/zdxt-enforcement-code-app/vite-env/.env.supervision-prod @@ -0,0 +1,5 @@ +# 监督端生产环境 +VITE_PORT = 12003 +VITE_BASE_URL = 'http://localhost:17000/sup-ep' +VITE_DEFAULT_LOGIN = '/supervision/login' +VITE_APP_ENV = 'prod' \ No newline at end of file diff --git a/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/AppEntEnterpriseInformationControllerTest.java b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/AppEntEnterpriseInformationControllerTest.java new file mode 100644 index 00000000..1b433faa --- /dev/null +++ b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/AppEntEnterpriseInformationControllerTest.java @@ -0,0 +1,338 @@ +package com.zdxt.rest.test; + +import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.dev33.satoken.stp.StpUtil; +import org.dromara.ZdxtAdminApplication; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.satoken.utils.LoginHelper; +import org.junit.jupiter.api.*; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import java.nio.charset.StandardCharsets; +import java.util.HashSet; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * AppEntEnterpriseInformationController 企业端-企业信息接口测试 + *

+ * 覆盖以下接口: + * 1. GET /app-ent/enterpriseInfo/getUserRefEnterpriseInfo - 根据用户ID获取关联企业信息 + * 2. GET /app-ent/enterpriseInfo/getQrCode/{enterpriseNumber} - 获取企业二维码 + * 3. GET /app-ent/enterpriseInfo/forceGenerateQrCode/{enterpriseNumber} - 强制生成二维码 + *

+ * + * @author zdxt + */ +@SpringBootTest(classes = ZdxtAdminApplication.class) +@AutoConfigureMockMvc +@DisplayName("AppEntEnterpriseInformationController 企业端-企业信息接口测试") +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class AppEntEnterpriseInformationControllerTest { + + @Autowired + private MockMvc mockMvc; + + private static final String BASE_URL = "/app-ent/enterpriseInfo"; + private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e"; + /** 测试用企业纳税识别号(需在数据库中存在) */ + private static final String TEST_ENTERPRISE_NUMBER = "91110000CTRL001"; + /** 测试用用户ID */ + private static final Long TEST_USER_ID = 1L; + + /** 登录后获取的 token */ + private String token; + + @BeforeEach + public void setUp() { + // 初始化 Sa-Token 上下文(非 Web 环境下 StpUtil.login 需要) + SaTokenContextMockUtil.setMockContext(); + + // 设置模拟请求上下文(UserActionListener 需要从 Request 中获取 User-Agent) + MockHttpServletRequest mockRequest = new MockHttpServletRequest(); + mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); + + // 构造测试用登录用户 + LoginUser loginUser = new LoginUser(); + loginUser.setUserId(TEST_USER_ID); + loginUser.setUserType("sys_user"); + loginUser.setTenantId("000000"); + loginUser.setUsername("test_admin"); + loginUser.setNickname("测试管理员"); + loginUser.setDeptId("103"); + loginUser.setDeptName("测试部门"); + loginUser.setRolePermission(new HashSet<>()); + loginUser.setMenuPermission(new HashSet<>()); + + // 模拟登录并获取 token + SaLoginParameter param = new SaLoginParameter(); + param.setExtra(LoginHelper.CLIENT_KEY, TEST_CLIENT_ID); + LoginHelper.login(loginUser, param); + token = StpUtil.getTokenValue(); + } + + @AfterEach + public void tearDown() { + try { + StpUtil.logout(); + } catch (Exception ignored) { + } + RequestContextHolder.resetRequestAttributes(); + SaTokenContextMockUtil.clearContext(); + } + + // ==================== getUserRefEnterpriseInfo 接口测试 ==================== + + @DisplayName("获取用户关联企业信息 - 正常请求") + @Test + @Order(1) + public void testGetUserRefEnterpriseInfo() throws Exception { + mockMvc.perform(get(BASE_URL + "/getUserRefEnterpriseInfo") + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID) + .param("userId", String.valueOf(TEST_USER_ID))) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.data").isArray()); + + System.out.println("获取用户关联企业信息接口测试成功"); + } + + @DisplayName("获取用户关联企业信息 - 缺少 userId 参数应返回失败") + @Test + @Order(1) + public void testGetUserRefEnterpriseInfoMissingUserId() throws Exception { + mockMvc.perform(get(BASE_URL + "/getUserRefEnterpriseInfo") + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } + + @DisplayName("获取用户关联企业信息 - 不存在的用户ID应返回空列表") + @Test + @Order(1) + public void testGetUserRefEnterpriseInfoNonExistUser() throws Exception { + mockMvc.perform(get(BASE_URL + "/getUserRefEnterpriseInfo") + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID) + .param("userId", "999999999")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.data").isArray()) + .andExpect(jsonPath("$.data.length()").value(0)); + + System.out.println("不存在用户ID返回空列表测试成功"); + } + + // ==================== getQrCode 接口测试 ==================== + + @DisplayName("获取企业二维码 - 正常请求") + @Test + @Order(2) + public void testGetQrCode() throws Exception { + MvcResult result = mockMvc.perform(get(BASE_URL + "/getQrCode/{enterpriseNumber}", TEST_ENTERPRISE_NUMBER) + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8); + System.out.println("获取企业二维码接口响应: " + responseBody); + + // 可能存在二维码记录也可能不存在,均为正常情况 + // 如果存在,验证返回数据结构 + if (responseBody.contains("\"code\":200")) { + Assertions.assertTrue(responseBody.contains("qrCodeUrl"), "返回数据应包含 qrCodeUrl"); + Assertions.assertTrue(responseBody.contains("enterpriseName"), "返回数据应包含 enterpriseName"); + Assertions.assertTrue(responseBody.contains("generateTime"), "返回数据应包含 generateTime"); + } + } + + @DisplayName("获取企业二维码 - 不存在的企业纳税识别号应返回失败") + @Test + @Order(2) + public void testGetQrCodeNonExistEnterprise() throws Exception { + mockMvc.perform(get(BASE_URL + "/getQrCode/{enterpriseNumber}", "NON_EXIST_NUMBER_999") + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(500)); + + System.out.println("不存在企业纳税识别号返回失败测试成功"); + } + + @DisplayName("获取企业二维码 - 空的企业纳税识别号应返回失败") + @Test + @Order(2) + public void testGetQrCodeEmptyEnterpriseNumber() throws Exception { + mockMvc.perform(get(BASE_URL + "/getQrCode/{enterpriseNumber}", " ") + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(500)); + + System.out.println("空企业纳税识别号返回失败测试成功"); + } + + // ==================== forceGenerateQrCode 接口测试 ==================== + + @DisplayName("强制生成二维码 - 正常请求") + @Test + @Order(3) + public void testForceGenerateQrCode() throws Exception { + MvcResult result = mockMvc.perform(get(BASE_URL + "/forceGenerateQrCode/{enterpriseNumber}", TEST_ENTERPRISE_NUMBER) + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8); + System.out.println("强制生成二维码接口响应: " + responseBody); + + // 如果企业存在,应返回成功并包含二维码信息 + if (responseBody.contains("\"code\":200")) { + Assertions.assertTrue(responseBody.contains("qrCodeUrl"), "返回数据应包含 qrCodeUrl"); + Assertions.assertTrue(responseBody.contains("enterpriseName"), "返回数据应包含 enterpriseName"); + Assertions.assertTrue(responseBody.contains("generateTime"), "返回数据应包含 generateTime"); + System.out.println("强制生成二维码接口测试成功"); + } + } + + @DisplayName("强制生成二维码 - 连续两次调用均应成功生成新二维码") + @Test + @Order(4) + public void testForceGenerateQrCodeTwice() throws Exception { + // 第一次强制生成 + MvcResult result1 = mockMvc.perform(get(BASE_URL + "/forceGenerateQrCode/{enterpriseNumber}", TEST_ENTERPRISE_NUMBER) + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + String body1 = result1.getResponse().getContentAsString(StandardCharsets.UTF_8); + + // 第二次强制生成(应生成新的二维码,不受已有记录影响) + MvcResult result2 = mockMvc.perform(get(BASE_URL + "/forceGenerateQrCode/{enterpriseNumber}", TEST_ENTERPRISE_NUMBER) + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + String body2 = result2.getResponse().getContentAsString(StandardCharsets.UTF_8); + + // 两次调用均应成功 + if (body1.contains("\"code\":200") && body2.contains("\"code\":200")) { + System.out.println("连续两次强制生成二维码均成功"); + // 两次生成的 qrCodeUrl 应不同(新二维码) + String url1 = extractJsonValue(body1, "qrCodeUrl"); + String url2 = extractJsonValue(body2, "qrCodeUrl"); + if (url1 != null && url2 != null) { + Assertions.assertNotEquals(url1, url2, "两次强制生成的二维码URL应不同"); + System.out.println("两次生成的二维码URL不同,验证通过"); + } + } + } + + @DisplayName("强制生成二维码 - 批量循环生成多个企业的二维码") + @Test + @Order(4) + public void testForceGenerateQrCodeNum() throws Exception { + String[] enterpriseNumbers = { + "91440300788302281W", + "914403007261811621", + "91440300662678582M", + "914403006820066603", + "91440300763461366N", + "91440300618837873J", + "91440300738848091F" + }; + + for (String enterpriseNumber : enterpriseNumbers) { + System.out.println("========== 开始强制生成二维码: " + enterpriseNumber + " =========="); + + MvcResult result = mockMvc.perform(get(BASE_URL + "/forceGenerateQrCode/{enterpriseNumber}", enterpriseNumber) + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8); + + if (responseBody.contains("\"code\":200")) { + Assertions.assertTrue(responseBody.contains("qrCodeUrl"), "返回数据应包含 qrCodeUrl"); + Assertions.assertTrue(responseBody.contains("enterpriseName"), "返回数据应包含 enterpriseName"); + Assertions.assertTrue(responseBody.contains("generateTime"), "返回数据应包含 generateTime"); + System.out.println("企业[" + enterpriseNumber + "]强制生成二维码成功"); + } else { + System.out.println("企业[" + enterpriseNumber + "]强制生成二维码响应: " + responseBody); + } + } + + System.out.println("========== 批量强制生成二维码全部完成 =========="); + } + + @DisplayName("强制生成二维码 - 不存在的企业纳税识别号应返回失败") + @Test + @Order(3) + public void testForceGenerateQrCodeNonExistEnterprise() throws Exception { + mockMvc.perform(get(BASE_URL + "/forceGenerateQrCode/{enterpriseNumber}", "NON_EXIST_NUMBER_999") + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(500)); + + System.out.println("不存在企业纳税识别号强制生成返回失败测试成功"); + } + + @DisplayName("强制生成二维码 - 空的企业纳税识别号应返回失败") + @Test + @Order(3) + public void testForceGenerateQrCodeEmptyEnterpriseNumber() throws Exception { + mockMvc.perform(get(BASE_URL + "/forceGenerateQrCode/{enterpriseNumber}", " ") + .header("Authorization", "Bearer " + token) + .header("clientid", TEST_CLIENT_ID)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(500)); + + System.out.println("空企业纳税识别号强制生成返回失败测试成功"); + } + + // ==================== 工具方法 ==================== + + /** + * 从 JSON 响应中简单提取指定字段的值 + */ + private String extractJsonValue(String responseBody, String key) { + if (responseBody != null && responseBody.contains("\"" + key + "\"")) { + int start = responseBody.indexOf("\"" + key + "\":\"") + key.length() + 4; + int end = responseBody.indexOf("\"", start); + if (start > 0 && end > start) { + return responseBody.substring(start, end); + } + } + return null; + } +}