Sfoglia il codice sorgente

@
fix: 按接入指南修正全部参数为安全发固定值

签约 (authorizeApply):
- personal_product_code: FUND_SAFT_SIGN_WITHHOLDING_P (接指§1.1)
- product_code: FUND_SAFT_SIGN_WITHHOLDING (接指§1.1)
- sign_scene: INDUSTRY|SATF_ACC 固定值 (接指§1.1,非代扣行业码)
- access_params.channel: QRCODE 扫码签约 (接指§1.1)
- third_party_type: PARTNER 必选 (接指§1.1)

充值 (deposit):
- product_code: FUND_ACCOUNT_BOOK (接指§2.3)
- biz_scene: SATF_DEPOSIT (接指§2.3)
- payee_info.ext_info: 必传 agreement_no (接指§2.3)
- time_expire: 必选 (接指§2.3)

开记账本 (createAccount): ext_info.agreement_no 必选 (接指§2.1)
查记账本 (queryAccounts): 改为按 account_book_id 查,ext_info 必传 (接指§2.2)
转账 (transfer): payer_info.ext_info.agreement_no 必选 (接指§3.2)

前端: 移除 sign_scene 下拉框弹窗及相关逻辑(安全发用固定值)
@

alphaH 1 giorno fa
parent
commit
eba321c81e

+ 3 - 3
frontend/src/api/module_payment/account.ts

@@ -43,7 +43,7 @@ export const AccountAPI = {
     });
   },
 
-  authorizeApply(data: { enterprise_id: string; sign_scene?: string }) {
+  authorizeApply(data: { enterprise_id: string }) {
     return request<ApiResponse<{ sign_url: string; external_agreement_no: string }>>({
       url: `${API_PATH}/authorize/apply`,
       method: "post",
@@ -51,11 +51,11 @@ export const AccountAPI = {
     });
   },
 
-  queryAgreement(enterpriseId: string, externalAgreementNo: string, signScene: string) {
+  queryAgreement(enterpriseId: string, externalAgreementNo: string) {
     return request<ApiResponse<{ agreement_no: string; status: string }>>({
       url: `${API_PATH}/agreement/query`,
       method: "get",
-      params: { enterprise_id: enterpriseId, external_agreement_no: externalAgreementNo, sign_scene: signScene },
+      params: { enterprise_id: enterpriseId, external_agreement_no: externalAgreementNo },
     });
   },
 

+ 2 - 62
frontend/src/views/module_payment/account/index.vue

@@ -510,26 +510,6 @@
     <TransferDetail v-model="transferDetailVisible" :out-biz-no="currentTransferOutBizNo"
       @refresh="handleTransferDetailRefresh" />
 
-    <!-- 签约场景码选择对话框 -->
-    <el-dialog v-model="signSceneDialogVisible" title="选择签约场景码" width="520px" :close-on-click-modal="false">
-      <el-form label-width="140px">
-        <el-form-item label="签约场景码 (sign_scene)">
-          <el-select v-model="authorizeResult.sign_scene" filterable placeholder="请选择行业场景码" style="width: 100%">
-            <el-option
-              v-for="item in SIGN_SCENE_OPTIONS"
-              :key="item.value"
-              :label="`${item.value} - ${item.label}`"
-              :value="item.value"
-            />
-          </el-select>
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <el-button @click="signSceneDialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="handleSignSceneConfirm">确认签约</el-button>
-      </template>
-    </el-dialog>
-
     <!-- 批量转账对话框 -->
     <el-dialog v-model="batchTransferVisible" title="批量转账" width="1000px" :close-on-click-modal="false" :close-on-press-escape="false">
       <div class="batch-transfer-container" :class="{ 'has-overlay': showBatchTransferOverlay }">
@@ -792,38 +772,6 @@ const authorizeForm = reactive({
   enterprise_id: "",
 });
 
-// 签约场景码 — 来自支付宝官方文档 https://opendocs.alipay.com/open/20190319114403226822/signscene
-const SIGN_SCENE_OPTIONS = [
-  { value: "INDUSTRY|LOTTERY", label: "彩票行业" },
-  { value: "INDUSTRY|SOCIALIZATION", label: "社交行业" },
-  { value: "INDUSTRY|MEDICAL", label: "医疗行业" },
-  { value: "INDUSTRY|APPSTORE", label: "电子商城行业" },
-  { value: "INDUSTRY|SUPERMARKET", label: "超市行业" },
-  { value: "INDUSTRY|B2B_TICKET_AGENT", label: "机票机构行业" },
-  { value: "INDUSTRY|CARRENTAL", label: "租车行业" },
-  { value: "INDUSTRY|GENERAL_TRAVEL", label: "出行行业" },
-  { value: "INDUSTRY|CATERING", label: "餐饮业" },
-  { value: "INDUSTRY|PURCHASE", label: "采购业" },
-  { value: "INDUSTRY|REPAYMENT", label: "信贷还款" },
-  { value: "INDUSTRY|DIGITAL_MEDIA", label: "数字传媒行业" },
-  { value: "INDUSTRY|GAME_CHARGE", label: "网游行业" },
-  { value: "INDUSTRY|BADGE_CONSUMPTION", label: "工牌消费" },
-  { value: "INDUSTRY|PARKING", label: "停车行业" },
-  { value: "INDUSTRY|MOBILE", label: "移动支付" },
-  { value: "INDUSTRY|TV", label: "电视支付" },
-  { value: "INDUSTRY|LEASE", label: "租借行业" },
-  { value: "INDUSTRY|EDU", label: "教育行业" },
-  { value: "INDUSTRY|VOICEPAY", label: "语音支付" },
-  { value: "INDUSTRY|FOREX_PLAT_PURCHASE", label: "境外平台采购" },
-  { value: "INDUSTRY|ALIPAYGO", label: "ALIPAYGO" },
-  { value: "INDUSTRY|TICKET", label: "票务行业" },
-  { value: "INDUSTRY|METRO", label: "地铁行业" },
-  { value: "INDUSTRY|VRPAY", label: "VR支付" },
-  { value: "INDUSTRY|LIFE_PAYMENT", label: "生活缴费行业" },
-];
-
-const signSceneDialogVisible = ref(false);
-
 const authorizeRules: FormRules = {
   enterprise_id: [{ required: true, message: "请输入企业ID", trigger: "blur" }],
 };
@@ -832,7 +780,6 @@ const authorizeResult = reactive({
   sign_url: "",
   external_agreement_no: "",
   agreement_no: "",
-  sign_scene: "INDUSTRY|PURCHASE",
   queryLoading: false,
 });
 
@@ -1275,16 +1222,10 @@ function resetBatchTransfer() {
   batchTransferFailCount.value = 0;
 }
 
-function handleSignSceneConfirm() {
-  signSceneDialogVisible.value = false;
-  handleAuthorize(authorizeResult.sign_scene);
-}
-
-async function handleAuthorize(signScene?: string) {
+async function handleAuthorize() {
   try {
     const res = await AccountAPI.authorizeApply({
       enterprise_id: currentEnterpriseId.value!,
-      sign_scene: signScene || authorizeResult.sign_scene || "DEFAULT|DEFAULT",
     });
     const signHtml = res.data.data?.sign_url || "";
     const externalAgreementNo = res.data.data?.external_agreement_no || "";
@@ -1310,7 +1251,6 @@ async function handleQueryAgreement() {
     const res = await AccountAPI.queryAgreement(
       currentEnterpriseId.value!,
       authorizeResult.external_agreement_no,
-      authorizeResult.sign_scene,
     );
     const agreementNo = res.data.data?.agreement_no || "";
     if (agreementNo) {
@@ -1749,7 +1689,7 @@ function handleOverviewRefresh(data: any) {
 async function handleGoTab(tab: string) {
   console.log("goTab => ", tab);
   if (tab === "authorize") {
-    signSceneDialogVisible.value = true;
+    await handleAuthorize();
   } else if (tab === "create") {
     await handleCreate();
   } else if (tab === "deposit") {

+ 3 - 6
java/src/main/java/com/payment/platform/module/payment/account/controller/AccountController.java

@@ -105,18 +105,15 @@ public class AccountController {
     @PreAuthorize("@perm.hasAny('module_payment:account:authorize')")
     @PostMapping("/authorize/apply")
     public Result<Map<String, String>> authorizeApply(@RequestBody Map<String, Object> b) {
-        return Result.ok(alipayTransferService.authorizeApply(
-                (String) b.get("enterprise_id"),
-                (String) b.getOrDefault("sign_scene", "DEFAULT|DEFAULT")));
+        return Result.ok(alipayTransferService.authorizeApply((String) b.get("enterprise_id")));
     }
 
     @PreAuthorize("@perm.hasAny('module_payment:account:authorize')")
     @GetMapping("/agreement/query")
     public Result<Map<String, String>> queryAgreement(
             @RequestParam(name = "enterprise_id") String enterpriseId,
-            @RequestParam(name = "external_agreement_no") String externalAgreementNo,
-            @RequestParam(name = "sign_scene", defaultValue = "DEFAULT|DEFAULT") String signScene) {
-        return Result.ok(alipayTransferService.queryAgreement(enterpriseId, externalAgreementNo, signScene));
+            @RequestParam(name = "external_agreement_no") String externalAgreementNo) {
+        return Result.ok(alipayTransferService.queryAgreement(enterpriseId, externalAgreementNo));
     }
 
     @PreAuthorize("@perm.hasAny('module_payment:account:create')")

+ 97 - 53
java/src/main/java/com/payment/platform/module/payment/account/service/AlipayTransferService.java

@@ -79,10 +79,22 @@ public class AlipayTransferService {
     @org.springframework.context.annotation.Lazy
     private com.payment.platform.module.payment.openapi.service.OpenapiService openapiService;
 
-    // ---- 安全发常量 ----
+    // ---- 安全发常量(来自接入指南 https://opendocs.alipay.com/pre-open/01ruru) ----
+    /** 签约: 个人产品码(固定值) */
+    private static final String SIGN_PERSONAL_PRODUCT_CODE = "FUND_SAFT_SIGN_WITHHOLDING_P";
+    /** 签约: 商户产品码(固定值) */
+    private static final String SIGN_PRODUCT_CODE = "FUND_SAFT_SIGN_WITHHOLDING";
+    /** 签约: 场景码(固定值,不是下拉选的代扣行业码) */
+    private static final String SIGN_SCENE = "INDUSTRY|SATF_ACC";
+    /** 转账: 产品码(固定值) */
     private static final String PRODUCT_CODE = "SINGLE_TRANSFER_NO_PWD";
+    /** 转账: 服务商版转账 */
     private static final String BIZ_SCENE_TRANSFER = "ENTRUST_TRANSFER";
-    private static final String BIZ_SCENE_ALLOCATION = "DIRECT_ALLOCATION";
+    /** 充值: 产品码(固定值) */
+    private static final String DEPOSIT_PRODUCT_CODE = "FUND_ACCOUNT_BOOK";
+    /** 充值: 场景码(固定值) */
+    private static final String BIZ_SCENE_DEPOSIT = "SATF_DEPOSIT";
+    /** 记账本场景码(固定值) */
     private static final String SCENE_CODE_ACCOUNT_BOOK = "SATF_FUND_BOOK";
 
     private static final Map<String, String> TRANSFER_ERROR_HINTS = new LinkedHashMap<>();
@@ -107,19 +119,20 @@ public class AlipayTransferService {
 
     /**
      * alipay.user.agreement.page.sign — 页面跳转接口
-     * 必填: personal_product_code, product_code, sign_scene, access_params
-     * sign_scene 由前端选择(external_agreement_no 不为空时不能为 DEFAULT|DEFAULT)
+     * 参数全部为安全发固定值,来自接入指南 §1.1
      */
-    public Map<String, String> authorizeApply(String enterpriseId, String signScene) {
+    public Map<String, String> authorizeApply(String enterpriseId) {
         String externalAgreementNo = enterpriseId + "_agreement";
         try {
             AlipayUserAgreementPageSignModel model = new AlipayUserAgreementPageSignModel();
-            model.setPersonalProductCode("GENERAL_WITHHOLDING_P");
-            model.setProductCode("GENERAL_WITHHOLDING");
-            model.setSignScene(signScene != null && !signScene.isBlank() ? signScene : "DEFAULT|DEFAULT");
-            model.setExternalAgreementNo(externalAgreementNo);
+            // 安全发固定值(接入指南 §1.1)
+            model.setPersonalProductCode(SIGN_PERSONAL_PRODUCT_CODE);
+            model.setProductCode(SIGN_PRODUCT_CODE);
+            model.setSignScene(SIGN_SCENE);
+            model.setThirdPartyType("PARTNER");               // 必选
+            model.setExternalAgreementNo(externalAgreementNo); // 必选
             AccessParams accessParams = new AccessParams();
-            accessParams.setChannel("ALIPAYAPP");
+            accessParams.setChannel("QRCODE");                 // 扫码签约
             model.setAccessParams(accessParams);
 
             AlipayUserAgreementPageSignRequest request = new AlipayUserAgreementPageSignRequest();
@@ -145,12 +158,13 @@ public class AlipayTransferService {
      * alipay.user.agreement.query — 通过 external_agreement_no 反查签约协议号
      * 用户完成签约后调用,获取支付宝侧的 agreement_no
      */
-    public Map<String, String> queryAgreement(String enterpriseId, String externalAgreementNo, String signScene) {
+    public Map<String, String> queryAgreement(String enterpriseId, String externalAgreementNo) {
         try {
             AlipayUserAgreementQueryModel model = new AlipayUserAgreementQueryModel();
             model.setExternalAgreementNo(externalAgreementNo);
-            model.setPersonalProductCode("GENERAL_WITHHOLDING_P");
-            model.setSignScene(signScene != null && !signScene.isBlank() ? signScene : "DEFAULT|DEFAULT");
+            // 安全发固定值(接入指南 §1.2)
+            model.setPersonalProductCode(SIGN_PERSONAL_PRODUCT_CODE);
+            model.setSignScene(SIGN_SCENE);
             model.setThirdPartyType("PARTNER");
 
             AlipayUserAgreementQueryRequest request = new AlipayUserAgreementQueryRequest();
@@ -201,12 +215,11 @@ public class AlipayTransferService {
             model.setMerchantUserType("BUSINESS_ORGANIZATION");
             model.setSceneCode(SCENE_CODE_ACCOUNT_BOOK);
 
-            if (agreementNo != null && !agreementNo.isBlank()) {
-                Map<String, String> extInfo = new LinkedHashMap<>();
-                extInfo.put("agreement_no", agreementNo);
-                try { model.setExtInfo(objectMapper.writeValueAsString(extInfo)); }
-                catch (Exception ignored) {}
-            }
+            // 接入指南 §2.1: ext_info 必选,agreement_no 必传
+            Map<String, String> extInfo = new LinkedHashMap<>();
+            extInfo.put("agreement_no", agreementNo != null ? agreementNo : "");
+            try { model.setExtInfo(objectMapper.writeValueAsString(extInfo)); }
+            catch (Exception e) { throw new BusinessException(400, "序列化 ext_info 失败"); }
 
             AlipayFundAccountbookCreateRequest request = new AlipayFundAccountbookCreateRequest();
             request.setBizModel(model);
@@ -237,21 +250,40 @@ public class AlipayTransferService {
     // ==================== 3. 充值(页面跳转) ====================
 
     /**
-     * alipay.fund.trans.page.pay — 页面跳转接口
-     * 必填: out_biz_no, trans_amount, product_code, biz_scene, payee_info
+     * alipay.fund.trans.page.pay — 页面跳转接口(接入指南 §2.3)
+     * 必填: out_biz_no, trans_amount, product_code=FUND_ACCOUNT_BOOK, biz_scene=SATF_DEPOSIT,
+     *       payee_info(identity_type=ACCOUNT_BOOK_ID, identity, ext_info含agreement_no), time_expire
      */
     @Transactional
     public Map<String, String> deposit(String enterpriseId, String accountBookId, BigDecimal amount, String remark) {
+        // 查询记账本获取 agreement_no(接入指南要求payee_info.ext_info必传)
+        AccountEntity account = accountMapper.selectOne(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AccountEntity>()
+                        .eq(AccountEntity::getAccountBookId, accountBookId));
+        String agreementNo = account != null ? account.getAgreementNo() : null;
+
         try {
             AlipayFundTransPagePayModel model = new AlipayFundTransPagePayModel();
             model.setOutBizNo(SnowflakeIdGenerator.nextIdStr());
             model.setTransAmount(amount.toPlainString());
-            model.setProductCode(PRODUCT_CODE);
-            model.setBizScene(BIZ_SCENE_ALLOCATION);
+            // 接入指南 §2.3: 充值专用产品码和场景码
+            model.setProductCode(DEPOSIT_PRODUCT_CODE);
+            model.setBizScene(BIZ_SCENE_DEPOSIT);
+            // 必选: 过期时间(格式 yyyy-MM-dd HH:mm)
+            model.setTimeExpire(java.time.LocalDateTime.now().plusHours(1)
+                    .format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
 
             Participant payee = new Participant();
             payee.setIdentityType("ACCOUNT_BOOK_ID");
             payee.setIdentity(accountBookId);
+            // 接入指南 §2.3: payee_info.ext_info 必传 agreement_no
+            if (agreementNo != null && !agreementNo.isBlank()) {
+                try {
+                    Map<String, String> ext = new LinkedHashMap<>();
+                    ext.put("agreement_no", agreementNo);
+                    payee.setExtInfo(objectMapper.writeValueAsString(ext));
+                } catch (Exception ignored) {}
+            }
             model.setPayeeInfo(payee);
 
             if (remark != null && !remark.isBlank()) model.setRemark(remark);
@@ -330,12 +362,11 @@ public class AlipayTransferService {
             Participant payer = new Participant();
             payer.setIdentityType("ACCOUNT_BOOK_ID");
             payer.setIdentity(account.getAccountBookId());
-            if (account.getAgreementNo() != null && !account.getAgreementNo().isBlank()) {
-                Map<String, String> payerExt = new LinkedHashMap<>();
-                payerExt.put("agreement_no", account.getAgreementNo());
-                try { payer.setExtInfo(objectMapper.writeValueAsString(payerExt)); }
-                catch (Exception ignored) {}
-            }
+            // 接入指南 §3.2: payer_info.ext_info.agreement_no 必传
+            Map<String, String> payerExt = new LinkedHashMap<>();
+            payerExt.put("agreement_no", account.getAgreementNo() != null ? account.getAgreementNo() : "");
+            try { payer.setExtInfo(objectMapper.writeValueAsString(payerExt)); }
+            catch (Exception e) { throw new BusinessException(400, "序列化 payer ext_info 失败"); }
             model.setPayerInfo(payer);
 
             // 必填: 收款方
@@ -433,34 +464,47 @@ public class AlipayTransferService {
     // ==================== 5. 查询记账本 ====================
 
     /**
-     * alipay.fund.accountbook.query
-     * 必填: merchant_user_id, scene_code
+     * alipay.fund.accountbook.query(接入指南 §2.2)
+     * 必填: account_book_id, scene_code, ext_info(含agreement_no)
      */
     public List<Map<String, Object>> queryAccounts(String enterpriseId) {
-        try {
-            AlipayFundAccountbookQueryModel model = new AlipayFundAccountbookQueryModel();
-            model.setMerchantUserId(enterpriseId);
-            model.setSceneCode(SCENE_CODE_ACCOUNT_BOOK);
-
-            AlipayFundAccountbookQueryRequest request = new AlipayFundAccountbookQueryRequest();
-            request.setBizModel(model);
-
-            AlipayFundAccountbookQueryResponse response =
-                    alipayClientFactory.getClient(enterpriseId).execute(request);
+        // 先从本地DB查记账本ID和协议号
+        var accounts = accountMapper.selectList(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AccountEntity>()
+                        .eq(AccountEntity::getEnterpriseId, enterpriseId));
+        if (accounts.isEmpty()) return List.of();
 
-            if (!response.isSuccess())
-                throw new BusinessException(400, "查询记账本失败: " + response.getMsg());
-
-            List<Map<String, Object>> result = new ArrayList<>();
-            Map<String, Object> m = new LinkedHashMap<>();
-            m.put("account_book_id", response.getAccountBookId());
-            m.put("available_amount", response.getAvailableAmount());
-            m.put("scene", "B2B_TRANS");
-            result.add(m);
-            return result;
-        } catch (AlipayApiException e) {
-            throw new BusinessException(400, "查询记账本失败: " + e.getMessage());
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (AccountEntity acc : accounts) {
+            try {
+                AlipayFundAccountbookQueryModel model = new AlipayFundAccountbookQueryModel();
+                model.setAccountBookId(acc.getAccountBookId());
+                model.setSceneCode(SCENE_CODE_ACCOUNT_BOOK);
+                // 接入指南 §2.2: ext_info 必选,含 agreement_no
+                Map<String, String> ext = new LinkedHashMap<>();
+                ext.put("agreement_no", acc.getAgreementNo() != null ? acc.getAgreementNo() : "");
+                model.setExtInfo(objectMapper.writeValueAsString(ext));
+
+                AlipayFundAccountbookQueryRequest request = new AlipayFundAccountbookQueryRequest();
+                request.setBizModel(model);
+
+                AlipayFundAccountbookQueryResponse response =
+                        alipayClientFactory.getClient(enterpriseId).execute(request);
+
+                if (response.isSuccess()) {
+                    Map<String, Object> m = new LinkedHashMap<>();
+                    m.put("account_book_id", response.getAccountBookId());
+                    m.put("available_amount", response.getAvailableAmount());
+                    m.put("scene", "B2B_TRANS");
+                    result.add(m);
+                }
+            } catch (AlipayApiException e) {
+                log.warn("查询记账本失败: account_book_id={}, err={}", acc.getAccountBookId(), e.getMessage());
+            } catch (Exception e) {
+                log.warn("序列化 ext_info 失败: {}", e.getMessage());
+            }
         }
+        return result;
     }
 
     // ==================== 6. 查询转账状态 ====================

+ 93 - 0
logs/payment-platform.log

@@ -118,3 +118,96 @@
 2026-07-15 11:37:53.434 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
 2026-07-15 11:38:53.440 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
 2026-07-15 11:38:53.493 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:39:53.500 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:39:53.552 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:40:53.567 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:40:53.613 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:41:53.628 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:41:53.673 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:42:53.685 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:42:53.730 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:43:53.743 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:43:53.819 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:44:53.822 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:44:53.867 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:45:53.868 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:45:53.946 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:46:53.951 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:46:53.996 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:47:29.818 [SpringApplicationShutdownHook] INFO  c.alibaba.druid.pool.DruidDataSource - {dataSource-1} closing ...
+2026-07-15 11:47:29.820 [SpringApplicationShutdownHook] INFO  c.alibaba.druid.pool.DruidDataSource - {dataSource-1} closed
+2026-07-15 11:47:35.083 [background-preinit] INFO  o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.1.Final
+2026-07-15 11:47:35.149 [main] INFO  c.p.platform.PaymentApplication - Starting PaymentApplication using Java 21.0.11 with PID 49688 (D:\project2\payment-platform\java\target\classes started by 1 in D:\project2\payment-platform)
+2026-07-15 11:47:35.150 [main] INFO  c.p.platform.PaymentApplication - The following 1 profile is active: "dev"
+2026-07-15 11:47:36.033 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
+2026-07-15 11:47:36.035 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
+2026-07-15 11:47:36.090 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 44 ms. Found 0 Redis repository interfaces.
+2026-07-15 11:47:36.654 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8001 (http)
+2026-07-15 11:47:36.662 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8001"]
+2026-07-15 11:47:36.663 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2026-07-15 11:47:36.663 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.20]
+2026-07-15 11:47:36.712 [main] INFO  o.a.c.c.C.[.[localhost].[/api/v1] - Initializing Spring embedded WebApplicationContext
+2026-07-15 11:47:36.712 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1426 ms
+2026-07-15 11:47:36.737 [main] INFO  c.a.d.s.b.a.DruidDataSourceAutoConfigure - Init DruidDataSource
+2026-07-15 11:47:38.162 [main] INFO  c.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
+2026-07-15 11:47:38.876 [main] WARN  c.p.p.c.alipay.AlipayClientFactory - 支付宝默认配置不完整,将仅使用服务商/租户专属客户端
+2026-07-15 11:47:39.029 [main] INFO  c.p.platform.core.oss.OssService - OSS client initialized: bucket=hunanxiaojunzioss, endpoint=oss-cn-beijing.aliyuncs.com
+2026-07-15 11:47:39.332 [main] INFO  c.p.p.m.p.e.s.EnterpriseNameSyncScheduler - [企业名称同步] 调度器启动
+2026-07-15 11:47:39.586 [main] INFO  c.p.p.m.p.n.s.NotificationService - 已注册 7 个通知处理器: [AccountHandler, BillHandler, EmployeeHandler, EnterpriseHandler, InstitutionHandler, OrderHandler, VoucherHandler]
+2026-07-15 11:47:40.085 [main] INFO  o.s.s.web.DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@3358805a, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@77e261e3, org.springframework.security.web.context.SecurityContextHolderFilter@2027d56f, org.springframework.security.web.header.HeaderWriterFilter@4a778943, org.springframework.web.filter.CorsFilter@642b71d6, org.springframework.security.web.authentication.logout.LogoutFilter@4f2b1a2f, com.payment.platform.core.security.JwtAuthFilter@3bf40c74, com.payment.platform.core.security.TenantApiKeyAuthFilter@54a033b8, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@64b20d9c, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@6fc3f1a7, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@93c66ef, org.springframework.security.web.session.SessionManagementFilter@365a4b9b, org.springframework.security.web.access.ExceptionTranslationFilter@3c2e73ce, org.springframework.security.web.access.intercept.AuthorizationFilter@46f041cb]
+2026-07-15 11:47:40.471 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8001"]
+2026-07-15 11:47:40.482 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8001 (http) with context path '/api/v1'
+2026-07-15 11:47:40.612 [main] INFO  c.p.platform.PaymentApplication - Started PaymentApplication in 6.057 seconds (process running for 6.644)
+2026-07-15 11:47:40.657 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:47:40.788 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:47:42.920 [main] INFO  c.p.p.core.config.AppStartupRunner - 系统配置缓存初始化完成
+2026-07-15 11:47:44.279 [main] INFO  c.p.p.core.config.AppStartupRunner - 数据字典缓存初始化完成 (10 个字典类型)
+2026-07-15 11:47:54.162 [tomcat-handler-0] INFO  o.a.c.c.C.[.[localhost].[/api/v1] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2026-07-15 11:47:54.162 [tomcat-handler-0] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2026-07-15 11:47:54.163 [tomcat-handler-0] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 1 ms
+2026-07-15 11:47:59.512 [tomcat-handler-0] INFO  c.p.p.c.alipay.AlipayClientFactory - 服务商[3]客户端创建成功, appId=2021006160682088, name=跨境服务商
+2026-07-15 11:48:40.801 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:48:40.847 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:49:16.317 [SpringApplicationShutdownHook] INFO  c.alibaba.druid.pool.DruidDataSource - {dataSource-1} closing ...
+2026-07-15 11:49:16.319 [SpringApplicationShutdownHook] INFO  c.alibaba.druid.pool.DruidDataSource - {dataSource-1} closed
+2026-07-15 11:49:20.618 [background-preinit] INFO  o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.1.Final
+2026-07-15 11:49:20.685 [main] INFO  c.p.platform.PaymentApplication - Starting PaymentApplication using Java 21.0.11 with PID 41904 (D:\project2\payment-platform\java\target\classes started by 1 in D:\project2\payment-platform)
+2026-07-15 11:49:20.686 [main] INFO  c.p.platform.PaymentApplication - The following 1 profile is active: "dev"
+2026-07-15 11:49:21.605 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
+2026-07-15 11:49:21.607 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
+2026-07-15 11:49:21.659 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 40 ms. Found 0 Redis repository interfaces.
+2026-07-15 11:49:22.195 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8001 (http)
+2026-07-15 11:49:22.202 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8001"]
+2026-07-15 11:49:22.203 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
+2026-07-15 11:49:22.204 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.20]
+2026-07-15 11:49:22.251 [main] INFO  o.a.c.c.C.[.[localhost].[/api/v1] - Initializing Spring embedded WebApplicationContext
+2026-07-15 11:49:22.252 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1417 ms
+2026-07-15 11:49:22.277 [main] INFO  c.a.d.s.b.a.DruidDataSourceAutoConfigure - Init DruidDataSource
+2026-07-15 11:49:23.704 [main] INFO  c.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
+2026-07-15 11:49:24.451 [main] WARN  c.p.p.c.alipay.AlipayClientFactory - 支付宝默认配置不完整,将仅使用服务商/租户专属客户端
+2026-07-15 11:49:24.604 [main] INFO  c.p.platform.core.oss.OssService - OSS client initialized: bucket=hunanxiaojunzioss, endpoint=oss-cn-beijing.aliyuncs.com
+2026-07-15 11:49:24.903 [main] INFO  c.p.p.m.p.e.s.EnterpriseNameSyncScheduler - [企业名称同步] 调度器启动
+2026-07-15 11:49:25.169 [main] INFO  c.p.p.m.p.n.s.NotificationService - 已注册 7 个通知处理器: [AccountHandler, BillHandler, EmployeeHandler, EnterpriseHandler, InstitutionHandler, OrderHandler, VoucherHandler]
+2026-07-15 11:49:25.694 [main] INFO  o.s.s.web.DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@642b71d6, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@93c66ef, org.springframework.security.web.context.SecurityContextHolderFilter@64b20d9c, org.springframework.security.web.header.HeaderWriterFilter@365a4b9b, org.springframework.web.filter.CorsFilter@7e916dc2, org.springframework.security.web.authentication.logout.LogoutFilter@53202b06, com.payment.platform.core.security.JwtAuthFilter@462b239f, com.payment.platform.core.security.TenantApiKeyAuthFilter@2ae08750, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7151dd9d, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1f596988, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1a18e68a, org.springframework.security.web.session.SessionManagementFilter@76efa2b7, org.springframework.security.web.access.ExceptionTranslationFilter@4a778943, org.springframework.security.web.access.intercept.AuthorizationFilter@493489dd]
+2026-07-15 11:49:26.063 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8001"]
+2026-07-15 11:49:26.075 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8001 (http) with context path '/api/v1'
+2026-07-15 11:49:26.157 [main] INFO  c.p.platform.PaymentApplication - Started PaymentApplication in 6.019 seconds (process running for 6.623)
+2026-07-15 11:49:26.199 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:49:26.321 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:49:28.515 [main] INFO  c.p.p.core.config.AppStartupRunner - 系统配置缓存初始化完成
+2026-07-15 11:49:29.509 [main] INFO  c.p.p.core.config.AppStartupRunner - 数据字典缓存初始化完成 (10 个字典类型)
+2026-07-15 11:49:32.531 [tomcat-handler-0] INFO  o.a.c.c.C.[.[localhost].[/api/v1] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2026-07-15 11:49:32.531 [tomcat-handler-0] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2026-07-15 11:49:32.533 [tomcat-handler-0] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms
+2026-07-15 11:49:33.020 [tomcat-handler-0] INFO  c.p.p.m.p.a.s.AlipayTransferService - 2088780082348345_agreement
+2026-07-15 11:49:33.110 [tomcat-handler-0] INFO  c.p.p.c.alipay.AlipayClientFactory - 服务商[3]客户端创建成功, appId=2021006160682088, name=跨境服务商
+2026-07-15 11:50:26.322 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:50:26.369 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:51:26.371 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:51:26.418 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:52:26.431 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:52:26.477 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:53:26.487 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:53:26.534 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易
+2026-07-15 11:54:26.538 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 定时任务开始执行
+2026-07-15 11:54:26.584 [scheduling-1] INFO  c.p.p.m.p.f.s.F2fTradePollScheduler - [收款轮询] 无待轮询交易