Pārlūkot izejas kodu

第三方接口调整提交代码

liuchengsen 1 mēnesi atpakaļ
vecāks
revīzija
9151270966

+ 9 - 9
zhijiayun-gateway/src/test/java/com/xuekairui/gateway/AdminLicenseTest.java

@@ -27,7 +27,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String body = """
                 {
                     "storeName": "审核测试大药房",
-                    "terminalType": "SINGLE",
+                    "terminalType": "SINGLE"
                     "province": "广东省",
                     "city": "深圳市",
                     "district": "南山区",
@@ -115,7 +115,7 @@ class AdminLicenseTest extends GatewayBaseTest {
                 {
                     "userId": 3,
                     "storeName": "管理员新增药房",
-                    "terminalType": "SINGLE",
+                    "terminalType": "SINGLE"
                     "province": "广东省",
                     "city": "深圳市",
                     "district": "福田区",
@@ -150,7 +150,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String body = """
                 {
                     "userId": 4,
-                    "terminalType": "SINGLE",
+                    "terminalType": "SINGLE"
                     "province": "广东省",
                     "city": "深圳市",
                     "district": "福田区",
@@ -175,7 +175,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String body = """
                 {
                     "storeName": "无客户药房",
-                    "terminalType": "SINGLE",
+                    "terminalType": "SINGLE"
                     "province": "广东省",
                     "city": "深圳市",
                     "district": "福田区",
@@ -212,7 +212,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String body = """
                 {
                     "storeName": "编辑后药房名称",
-                    "terminalType": "CHAIN",
+                    "terminalType": "CHAIN"
                     "province": "北京市",
                     "city": "北京市",
                     "district": "海淀区",
@@ -239,7 +239,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String body = """
                 {
                     "storeName": "编辑测试药房",
-                    "terminalType": "SINGLE",
+                    "terminalType": "SINGLE"
                     "province": "广东省",
                     "city": "深圳市",
                     "district": "南山区",
@@ -263,7 +263,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String body = """
                 {
                     "storeName": "不存在的药房",
-                    "terminalType": "SINGLE",
+                    "terminalType": "SINGLE"
                     "province": "广东省",
                     "city": "深圳市",
                     "district": "南山区",
@@ -407,7 +407,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String uploadBody = """
                 {
                     "storeName": "拒绝测试药房",
-                    "terminalType": "CHAIN",
+                    "terminalType": "CHAIN"
                     "province": "北京市",
                     "city": "北京市",
                     "district": "朝阳区",
@@ -449,7 +449,7 @@ class AdminLicenseTest extends GatewayBaseTest {
         String uploadBody = """
                 {
                     "storeName": "驳回原因测试药房",
-                    "terminalType": "CLINIC",
+                    "terminalType": "CLINIC"
                     "province": "上海市",
                     "city": "上海市",
                     "district": "浦东新区",

+ 1 - 1
zhijiayun-gateway/src/test/java/com/xuekairui/gateway/BusinessLicenseAndCouponTest.java

@@ -31,7 +31,7 @@ class BusinessLicenseAndCouponTest extends GatewayBaseTest {
         String body = """
                 {
                     "storeName": "测试大药房",
-                    "terminalType": "SINGLE",
+                    "terminalType": "SINGLE"
                     "province": "广东省",
                     "city": "深圳市",
                     "district": "南山区",

+ 2 - 1
zhijiayun-invite/src/main/java/com/xuekairui/invite/service/InviteService.java

@@ -1020,7 +1020,8 @@ public class InviteService {
                     .inviteePhone(inviteePhone)
                     .inviteeMembershipLevel(inviteeLevel)
                     .registered(r.getRegistered() != null ? r.getRegistered() : 0)
-                    .registeredText(isRegistered ? "已注册" : "待注册")
+                    .registeredText(LicenseStatus.fromDb(
+                            licenseStatusMap.get(r.getInviteeId())).getDisplayText())
                     .rewardCount(r.getRewardGranted())
                     .inviteCode(r.getInviteCodeId() != null ? codeMap.get(r.getInviteCodeId()) : null)
                     .licenseStatus(licenseStatusMap.getOrDefault(r.getInviteeId(), LicenseStatus.NOT_SUBMITTED.name()))

+ 1 - 1
zhijiayun-user/src/main/java/com/xuekairui/user/dto/ExternalTokenRequest.java

@@ -57,7 +57,7 @@ public class ExternalTokenRequest {
     /** 可选:店铺名称(不传则用 pharmacyName 兜底) */
     private String storeName;
 
-    /** 可选:终端类型 */
+    /** 可选:终端类型:SINGLE-单店, CHAIN-连锁, CLINIC-诊所, COMMUNITY_HEALTH-社康 */
     private String terminalType;
 
     /** 可选:营业执照图片URL */

+ 15 - 4
zhijiayun-user/src/main/java/com/xuekairui/user/enums/LicenseStatus.java

@@ -28,16 +28,27 @@ package com.xuekairui.user.enums;
 public enum LicenseStatus {
 
     /** 待入驻 — 用户尚未提交入驻信息(DB 中无记录,仅逻辑状态) */
-    NOT_SUBMITTED,
+    NOT_SUBMITTED("待入驻"),
 
     /** 待审核 — 用户已提交,等待运营审核 */
-    PENDING,
+    PENDING("待审核"),
 
     /** 已通过 — 运营审核通过,展示认证标识 */
-    APPROVED,
+    APPROVED("已入驻"),
 
     /** 已驳回 — 运营审核驳回,含驳回原因,用户可重新提交 */
-    REJECTED;
+    REJECTED("已驳回");
+
+    private final String displayText;
+
+    LicenseStatus(String displayText) {
+        this.displayText = displayText;
+    }
+
+    /** 获取用户端展示文本 */
+    public String getDisplayText() {
+        return displayText;
+    }
 
     /**
      * 是否为最终态(不可再审核操作)

+ 14 - 11
zhijiayun-user/src/main/java/com/xuekairui/user/service/AuthService.java

@@ -645,16 +645,16 @@ public class AuthService {
                 .build();
     }
 
-    /** 映射第三方 shop_type → 内部 terminalType */
-    private static String mapShopType(String shopType) {
-        if (shopType == null) {
+    /** 第三方 shop_type → 内部枚举字符串,兼容数字 "1"/"2"/"3" 和英文 */
+    private static String parseShopType(String shopType) {
+        if (shopType == null || shopType.isBlank()) {
             return null;
         }
         return switch (shopType) {
-            case "1" -> "SINGLE";
-            case "2" -> "CHAIN";
-            case "3" -> "CLINIC";
-            default -> shopType;
+            case "1", "SINGLE" -> "SINGLE";
+            case "2", "CHAIN" -> "CHAIN";
+            case "3", "CLINIC", "COMMUNITY_HEALTH" -> "CLINIC";
+            default -> shopType; // 未知值原样保留
         };
     }
 
@@ -698,11 +698,11 @@ public class AuthService {
     /** 同步入驻信息到 t_business_license */
     private void syncBusinessLicenseFromShopReport(SyncShopReportRequest req, Long userId) {
         String storeName = isNotBlank(req.getContactShop()) ? req.getContactShop() : null;
-        String terminalType = mapShopType(req.getShopType());
+        String terminalType = parseShopType(req.getShopType());
         int status = mapStatus(req.getStatus());
 
         boolean hasLicenseField = isNotBlank(storeName)
-                || isNotBlank(terminalType)
+                || terminalType != null
                 || isNotBlank(req.getBusinessLicenseImage())
                 || isNotBlank(req.getDrugBusinessLicenseImage())
                 || isNotBlank(req.getTwoMedicalDeviceRegistration())
@@ -958,8 +958,11 @@ public class AuthService {
         String storeName = (request.getStoreName() != null && !request.getStoreName().isBlank())
                 ? request.getStoreName() : request.getPharmacyName();
 
+        // 第三方终端类型(可能是数字字符串1/2/3),统一转换
+        String terminalType = parseShopType(request.getTerminalType());
+
         boolean hasLicenseField = isNotBlank(storeName)
-                || isNotBlank(request.getTerminalType())
+                || terminalType != null
                 || isNotBlank(request.getBusinessLicenseUrl())
                 || isNotBlank(request.getDrugLicenseUrl())
                 || isNotBlank(request.getMedicalDeviceClass2Url())
@@ -988,7 +991,7 @@ public class AuthService {
                     com.xuekairui.user.entity.BusinessLicense.builder()
                             .userId(userId)
                             .storeName(storeName)
-                            .terminalType(request.getTerminalType())
+                            .terminalType(terminalType)
                             .province(request.getProvince())
                             .city(request.getCity())
                             .district(request.getDistrict())

+ 0 - 156
zhijiayun-user/src/main/java/com/xuekairui/user/service/ThirdPartySyncClient.java

@@ -1,156 +0,0 @@
-package com.xuekairui.user.service;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.xuekairui.user.config.ThirdPartySyncProperties;
-import com.xuekairui.user.dto.SyncShopReportRequest;
-import com.xuekairui.user.dto.ThirdPartySyncResponse;
-import com.xuekairui.user.entity.BusinessLicense;
-import com.xuekairui.user.entity.User;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestClient;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * 我方 → 第三方 同步客户端
- * <p>调用第三方 POST /api/sync_shop_resource/report_user(query 参数,snake_case)
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class ThirdPartySyncClient {
-
-    private final ThirdPartySyncProperties properties;
-    private final RestClient restClient;
-    private final ObjectMapper objectMapper;
-
-    /**
-     * 同步用户店铺信息到第三方
-     *
-     * @return 第三方响应(含 token、user_id 等);失败返回 null
-     */
-    public ThirdPartySyncResponse syncToThirdParty(SyncShopReportRequest request) {
-        try {
-            Map<String, String> queryParams = toQueryParams(request);
-            String uri = UriComponentsBuilder.fromPath(properties.getSyncPath())
-                    .queryParams(toMultiValueMap(queryParams))
-                    .build()
-                    .toUriString();
-
-            ThirdPartySyncResponse response = restClient.post()
-                    .uri(uri)
-                    .retrieve()
-                    .body(ThirdPartySyncResponse.class);
-
-            if (response != null && "success".equals(response.getCode())) {
-                log.info("同步到第三方成功: phone={}, thirdUserId={}",
-                        request.getPhone(),
-                        response.getData() != null ? response.getData().getUserId() : null);
-            } else {
-                log.warn("同步到第三方返回非成功: phone={}, code={}, msg={}",
-                        request.getPhone(),
-                        response != null ? response.getCode() : null,
-                        response != null ? response.getMsg() : null);
-            }
-            return response;
-        } catch (Exception e) {
-            log.error("同步到第三方失败: phone={}, error={}", request.getPhone(), e.getMessage(), e);
-            return null;
-        }
-    }
-
-    /**
-     * 使用 Jackson @JsonProperty 将 DTO 序列化为 snake_case 的 query 参数 Map
-     */
-    private Map<String, String> toQueryParams(SyncShopReportRequest req) {
-        Map<String, String> params = new LinkedHashMap<>();
-        JsonNode node = objectMapper.valueToTree(req);
-        node.fields().forEachRemaining(entry -> {
-            if (!entry.getValue().isNull()) {
-                params.put(entry.getKey(), entry.getValue().asText());
-            }
-        });
-        return params;
-    }
-
-    private static org.springframework.util.MultiValueMap<String, String> toMultiValueMap(
-            Map<String, String> map) {
-        org.springframework.util.LinkedMultiValueMap<String, String> multiMap =
-                new org.springframework.util.LinkedMultiValueMap<>();
-        map.forEach(multiMap::add);
-        return multiMap;
-    }
-
-    /**
-     * 根据我方 User 实体构建同步请求
-     */
-    public SyncShopReportRequest buildRequest(User user) {
-        SyncShopReportRequest req = new SyncShopReportRequest();
-        req.setPhone(user.getPhone());
-        req.setContactName(user.getNickname());
-        req.setContactPhone(user.getContactPhone());
-        req.setContactShop(user.getPharmacyName());
-        req.setContactProvince(user.getProvince());
-        req.setContactCity(user.getCity());
-        req.setContactArea(user.getDistrict());
-        req.setContactAddr(user.getPharmacyAddress());
-        req.setAppId(properties.getAppId());
-        req.setUserType("1");
-        req.setOperatorUserid("0");
-        return req;
-    }
-
-    /**
-     * 根据我方 User + BusinessLicense 实体构建完整同步请求
-     */
-    public SyncShopReportRequest buildRequest(User user, BusinessLicense license) {
-        SyncShopReportRequest req = buildRequest(user);
-        if (license != null) {
-            req.setContactShop(license.getStoreName() != null ? license.getStoreName() : req.getContactShop());
-            req.setContactProvince(license.getProvince() != null ? license.getProvince() : req.getContactProvince());
-            req.setContactCity(license.getCity() != null ? license.getCity() : req.getContactCity());
-            req.setContactArea(license.getDistrict() != null ? license.getDistrict() : req.getContactArea());
-            req.setContactAddr(license.getStoreAddress() != null ? license.getStoreAddress() : req.getContactAddr());
-            req.setContactName(license.getContactPerson() != null ? license.getContactPerson() : req.getContactName());
-            req.setContactPhone(license.getContactPhone() != null ? license.getContactPhone() : req.getContactPhone());
-            req.setBusinessLicenseImage(license.getLicenseImageUrl());
-            req.setDrugBusinessLicenseImage(license.getDrugLicenseUrl());
-            req.setTwoMedicalDeviceRegistration(license.getMedicalDeviceClass2Url());
-            req.setThreeMedicalDeviceBusinessLicense(license.getMedicalDeviceClass3Url());
-            // shop_type: 反向映射 terminalType → 第三方编码
-            req.setShopType(mapShopTypeToThirdParty(license.getTerminalType()));
-            // status: 反向映射 reviewStatus → 第三方编码
-            req.setStatus(mapStatusToThirdParty(license.getReviewStatus()));
-        }
-        req.setAppId(properties.getAppId());
-        req.setUserType("1");
-        req.setOperatorUserid("0");
-        return req;
-    }
-
-    /** terminalType → 第三方编码 */
-    private static String mapShopTypeToThirdParty(String terminalType) {
-        if (terminalType == null) return null;
-        return switch (terminalType) {
-            case "SINGLE" -> "1";
-            case "CHAIN" -> "2";
-            case "CLINIC", "COMMUNITY_HEALTH" -> "3";
-            default -> terminalType;
-        };
-    }
-
-    /** reviewStatus → 第三方编码 */
-    private static String mapStatusToThirdParty(String reviewStatus) {
-        if (reviewStatus == null) return "0";
-        return switch (reviewStatus) {
-            case "APPROVED" -> "1";
-            case "REJECTED" -> "2";
-            default -> "0";
-        };
-    }
-}

+ 5 - 4
zhijiayun-user/src/main/java/com/xuekairui/user/service/impl/ShopResourceSyncServiceImpl.java

@@ -85,6 +85,7 @@ public class ShopResourceSyncServiceImpl implements ShopResourceSyncService {
         params.put("contact_addr", nullToEmpty(license.getStoreAddress()));
         params.put("contact_name", nullToEmpty(license.getContactPerson()));
         params.put("contact_shop", nullToEmpty(license.getStoreName()));
+        // 内部 SINGLE/CHAIN/CLINIC → 第三方 1/2/3
         params.put("shop_type", mapTerminalType(license.getTerminalType()));
         params.put("contact_phone", nullToEmpty(license.getContactPhone()));
         params.put("business_license_image", nullToEmpty(license.getLicenseImageUrl()));
@@ -116,17 +117,17 @@ public class ShopResourceSyncServiceImpl implements ShopResourceSyncService {
     }
 
     /**
-     * 终端类型映射:我方枚举 → 第三方数字编码
-     * SINGLE-单店→1, CHAIN-连锁→2, CLINIC/COMMUNITY_HEALTH-诊所社康等→3
+     * 终端类型映射:内部 SINGLE/CHAIN/CLINIC → 第三方 1/2/3
      */
     private String mapTerminalType(String terminalType) {
         if (terminalType == null) {
-            return "3";
+            return "3"; // 默认诊所
         }
         return switch (terminalType) {
             case "SINGLE" -> "1";
             case "CHAIN" -> "2";
-            default -> "3";
+            case "CLINIC", "COMMUNITY_HEALTH" -> "3";
+            default -> terminalType; // 未知原样
         };
     }