|
|
@@ -0,0 +1,130 @@
|
|
|
+package com.payment.platform.module.payment.batch.service;
|
|
|
+
|
|
|
+import com.alipay.api.AlipayApiException;
|
|
|
+import com.alipay.api.AlipayClient;
|
|
|
+import com.alipay.api.domain.AlipayFundAuthorizeUniApplyModel;
|
|
|
+import com.alipay.api.domain.AlipayFundAuthorizeUniQueryModel;
|
|
|
+import com.alipay.api.domain.AuthParticipantInfo;
|
|
|
+import com.alipay.api.request.AlipayFundAuthorizeUniApplyRequest;
|
|
|
+import com.alipay.api.request.AlipayFundAuthorizeUniQueryRequest;
|
|
|
+import com.alipay.api.response.AlipayFundAuthorizeUniApplyResponse;
|
|
|
+import com.alipay.api.response.AlipayFundAuthorizeUniQueryResponse;
|
|
|
+import com.payment.platform.common.exception.BusinessException;
|
|
|
+import com.payment.platform.common.response.PageResult;
|
|
|
+import com.payment.platform.common.utils.ExcelUtil;
|
|
|
+import com.payment.platform.common.utils.SnowflakeIdGenerator;
|
|
|
+import com.payment.platform.core.alipay.AlipayClientFactory;
|
|
|
+import com.payment.platform.module.payment.batch.entity.BatchAuthorizeEntity;
|
|
|
+import com.payment.platform.module.payment.batch.entity.BatchDetailEntity;
|
|
|
+import com.payment.platform.module.payment.batch.entity.BatchOrderEntity;
|
|
|
+import com.payment.platform.module.payment.batch.mapper.BatchAuthorizeMapper;
|
|
|
+import com.payment.platform.module.payment.batch.mapper.BatchDetailMapper;
|
|
|
+import com.payment.platform.module.payment.batch.mapper.BatchOrderMapper;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.time.OffsetDateTime;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 批量付款到户有密 — 制单授权
|
|
|
+ * <p>
|
|
|
+ * 授权链路: authorizeApply 生成短链(PC) → 付款方端内授权(永久生效) →
|
|
|
+ * fund.authorize.status.notify 异步通知回写 agreement_no。
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class AlipayBatchPayService {
|
|
|
+
|
|
|
+ private static final String AUTHORIZE_PRODUCT_CODE = "TRANSFER_API_STANDARD_AUTHORIZATION";
|
|
|
+ private static final String AUTHORIZE_BIZ_SCENE = "STANDARD_CREATE_FUND_ORDER";
|
|
|
+ private static final String AUTHORIZE_LINK_TYPE = "SHORT_URL";
|
|
|
+ private static final String BIZ_TYPE = "BATCH_PAY";
|
|
|
+
|
|
|
+ /** 静态 ObjectMapper(同 NotificationService 第 55 行模式),用于 ext_info / 报备 JSON 序列化 */
|
|
|
+ private static final ObjectMapper oMapper = new ObjectMapper();
|
|
|
+
|
|
|
+ private final AlipayClientFactory alipayClientFactory;
|
|
|
+ private final BatchAuthorizeMapper batchAuthorizeMapper;
|
|
|
+
|
|
|
+ /** alipay.fund.authorize.uni.apply — 生成制单授权短链接(PC 渠道) */
|
|
|
+ @Transactional
|
|
|
+ public Map<String, String> authorizeApply(String enterpriseId, String participantId) {
|
|
|
+ if (participantId == null || participantId.isBlank())
|
|
|
+ throw new BusinessException(400, "付款方支付宝账号不能为空");
|
|
|
+ String outBizNo = SnowflakeIdGenerator.nextIdStr();
|
|
|
+ try {
|
|
|
+ AlipayFundAuthorizeUniApplyModel model = new AlipayFundAuthorizeUniApplyModel();
|
|
|
+ model.setProductCode(AUTHORIZE_PRODUCT_CODE);
|
|
|
+ model.setBizScene(AUTHORIZE_BIZ_SCENE);
|
|
|
+ model.setOutBizNo(outBizNo);
|
|
|
+ model.setAuthorizeLinkType(AUTHORIZE_LINK_TYPE);
|
|
|
+ model.setChannel("pc");
|
|
|
+ AuthParticipantInfo principal = new AuthParticipantInfo();
|
|
|
+ principal.setParticipantId(participantId);
|
|
|
+ principal.setParticipantIdType("ALIPAY_USER_ID");
|
|
|
+ model.setPrincipalInfo(principal);
|
|
|
+
|
|
|
+ AlipayFundAuthorizeUniApplyRequest request = new AlipayFundAuthorizeUniApplyRequest();
|
|
|
+ request.setBizModel(model);
|
|
|
+ AlipayClient client = alipayClientFactory.getClient(enterpriseId, BIZ_TYPE);
|
|
|
+ AlipayFundAuthorizeUniApplyResponse response = client.certificateExecute(request);
|
|
|
+ if (!response.isSuccess())
|
|
|
+ throw new BusinessException(400, "生成授权链接失败: " + response.getMsg());
|
|
|
+
|
|
|
+ BatchAuthorizeEntity entity = new BatchAuthorizeEntity();
|
|
|
+ entity.setEnterpriseId(enterpriseId);
|
|
|
+ entity.setOutBizNo(outBizNo);
|
|
|
+ entity.setParticipantId(participantId);
|
|
|
+ entity.setParticipantIdType("ALIPAY_USER_ID");
|
|
|
+ entity.setStatus("AUTHING");
|
|
|
+ entity.setAuthorizeLink(response.getAuthorizeLink());
|
|
|
+ batchAuthorizeMapper.insert(entity);
|
|
|
+
|
|
|
+ return Map.of("authorize_link", response.getAuthorizeLink(),
|
|
|
+ "out_biz_no", outBizNo, "status", "AUTHING");
|
|
|
+ } catch (AlipayApiException e) {
|
|
|
+ throw new BusinessException(400, "生成授权链接失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** alipay.fund.authorize.uni.query — 查询制单授权状态(单协议) */
|
|
|
+ public Map<String, String> queryAuthorize(String enterpriseId, String outBizNo) {
|
|
|
+ try {
|
|
|
+ AlipayFundAuthorizeUniQueryModel model = new AlipayFundAuthorizeUniQueryModel();
|
|
|
+ model.setProductCode(AUTHORIZE_PRODUCT_CODE);
|
|
|
+ model.setBizScene(AUTHORIZE_BIZ_SCENE);
|
|
|
+ model.setOutBizNo(outBizNo);
|
|
|
+
|
|
|
+ AlipayFundAuthorizeUniQueryRequest request = new AlipayFundAuthorizeUniQueryRequest();
|
|
|
+ request.setBizModel(model);
|
|
|
+ AlipayFundAuthorizeUniQueryResponse response =
|
|
|
+ alipayClientFactory.getClient(enterpriseId, BIZ_TYPE).certificateExecute(request);
|
|
|
+ if (!response.isSuccess())
|
|
|
+ throw new BusinessException(400, "查询授权状态失败: " + response.getMsg());
|
|
|
+
|
|
|
+ if (response.getAgreementNo() != null && !response.getAgreementNo().isBlank()) {
|
|
|
+ BatchAuthorizeEntity entity = batchAuthorizeMapper.selectOne(
|
|
|
+ new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<BatchAuthorizeEntity>()
|
|
|
+ .eq(BatchAuthorizeEntity::getOutBizNo, outBizNo));
|
|
|
+ if (entity != null) {
|
|
|
+ entity.setAgreementNo(response.getAgreementNo());
|
|
|
+ entity.setStatus("AUTHED");
|
|
|
+ batchAuthorizeMapper.updateById(entity);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Map.of("agreement_no", response.getAgreementNo() != null ? response.getAgreementNo() : "",
|
|
|
+ "status", response.getStatus() != null ? response.getStatus() : "AUTHING");
|
|
|
+ } catch (AlipayApiException e) {
|
|
|
+ throw new BusinessException(400, "查询授权状态失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|