feat(qywx): 新增企业微信API相关功能及响应类

- 新增NewsArticle、NewsMessageResponse、GetAuthInfoResult等响应类,用于处理企业微信API的返回数据
- 在QywxApiUtil中新增sendNewsMessage和getAuthInfo方法,支持发送图文消息和获取企业授权信息
- 在QywxController中新增getAuthInfo接口,用于获取企业授权信息
- 在ReturnApprovalApplicationService中更新商品库存逻辑,确保退货审批通过后更新商品库存
This commit is contained in:
dzq 2025-04-14 08:10:38 +08:00
parent 14b32f6d07
commit 2453b7bea7
8 changed files with 1098 additions and 8 deletions

View File

@ -5,6 +5,8 @@ import com.agileboot.api.customize.async.QyAsyncTaskFactory;
import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.utils.weixin.aes.WXBizMsgCrypt; import com.agileboot.common.utils.weixin.aes.WXBizMsgCrypt;
import com.agileboot.domain.qywx.api.QywxApiUtil;
import com.agileboot.domain.qywx.api.response.GetAuthInfoResult;
import com.agileboot.domain.qywx.auth.AuthApplicationService; import com.agileboot.domain.qywx.auth.AuthApplicationService;
import com.agileboot.domain.qywx.auth.command.AddAuthCommand; import com.agileboot.domain.qywx.auth.command.AddAuthCommand;
import com.agileboot.domain.qywx.authCorpInfo.AuthCorpInfoApplicationService; import com.agileboot.domain.qywx.authCorpInfo.AuthCorpInfoApplicationService;
@ -82,6 +84,16 @@ public class QywxController {
} }
} }
@GetMapping("/getAuthInfo")
public GetAuthInfoResult getAuthInfo(@RequestParam String suiteAccessToken, @RequestParam String corpid, @RequestParam String permanentCode) {
try {
return QywxApiUtil.getAuthInfo(suiteAccessToken, corpid, permanentCode);
} catch (Exception e) {
log.error("getAuthInfo error", e);
throw new ApiException(ErrorCode.FAILED, "获取企业授权信息失败", e);
}
}
@GetMapping("/callback/data") @GetMapping("/callback/data")
public String validateDataCallback(@RequestParam String msg_signature, public String validateDataCallback(@RequestParam String msg_signature,
@RequestParam String timestamp, @RequestParam String timestamp,

View File

@ -1,21 +1,16 @@
package com.agileboot.api.customize.async; package com.agileboot.api.customize.async;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.agileboot.domain.qywx.auth.db.QyAuthService; import com.agileboot.domain.qywx.api.response.GetAuthInfoResult;
import com.agileboot.domain.qywx.authCorpInfo.AuthCorpInfoApplicationService; import com.agileboot.domain.qywx.authCorpInfo.AuthCorpInfoApplicationService;
import com.agileboot.domain.qywx.authCorpInfo.command.AddAuthCorpInfoCommand; import com.agileboot.domain.qywx.authCorpInfo.command.AddAuthCorpInfoCommand;
import com.agileboot.domain.qywx.authCorpInfo.command.UpdateAuthCorpInfoCommand; import com.agileboot.domain.qywx.authCorpInfo.command.UpdateAuthCorpInfoCommand;
import com.agileboot.domain.qywx.authCorpInfo.db.QyAuthCorpInfoService;
import com.agileboot.domain.qywx.template.TemplateApplicationService;
import com.agileboot.domain.qywx.template.db.QyTemplateEntity;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
@Slf4j @Slf4j
public class QyAsyncTaskFactory { public class QyAsyncTaskFactory {

View File

@ -1,5 +1,6 @@
package com.agileboot.domain.qywx.api; package com.agileboot.domain.qywx.api;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.ApiException;
@ -11,12 +12,43 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
@Slf4j @Slf4j
public class QywxApiUtil { public class QywxApiUtil {
/**
* 发送图文消息
* @param accessToken 接口调用凭证
* @param agentId 应用ID
* @param toUser 成员ID列表多个用|分隔
* @param articles 图文条目列表
* @return 消息发送结果
*/
public static NewsMessageResponse sendNewsMessage(String accessToken, Integer agentId, String toUser, List<NewsArticle> articles) {
String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken;
Map<String, Object> params = new HashMap<>();
params.put("touser", toUser);
params.put("msgtype", "news");
params.put("agentid", agentId);
params.put("news", Collections.singletonMap("articles", JSONUtil.parse(articles)));
String paramJson = JSONUtil.toJsonStr(params);
String response = HttpUtil.post(url, paramJson);
log.info("sendNewsMessage response: {}", response);
NewsMessageResponse result = JSONUtil.toBean(response, NewsMessageResponse.class);
if (result.getErrcode() != 0) {
throw new ApiException(ErrorCode.Internal.INTERNAL_ERROR,
String.format("发送图文消息失败: %s", result.getErrmsg()));
}
return result;
}
/** /**
* 获取企业微信部门列表简易信息 * 获取企业微信部门列表简易信息
* @param access_token 企业微信接口调用凭证 * @param access_token 企业微信接口调用凭证
@ -125,5 +157,18 @@ public class QywxApiUtil {
throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "微信服务调用失败"); throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "微信服务调用失败");
} }
} }
public static GetAuthInfoResult getAuthInfo(String suiteAccessToken, String corpid, String permanentCode) {
String url = "https://qyapi.weixin.qq.com/cgi-bin/service/v2/get_auth_info?suite_access_token="+suiteAccessToken;
Map<String, String> requestBody = new HashMap<String, String>();
requestBody.put("auth_corpid", corpid);
requestBody.put("permanent_code", permanentCode);
String response = HttpUtil.post(url, JSONUtil.toJsonStr(requestBody));
log.info("getAuthInfo response: {}", response);
return JSONUtil.toBean(response, GetAuthInfoResult.class);
}
} }

View File

@ -1,4 +1,4 @@
package com.agileboot.api.customize.async; package com.agileboot.domain.qywx.api.response;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import lombok.Data; import lombok.Data;

View File

@ -0,0 +1,35 @@
package com.agileboot.domain.qywx.api.response;
import lombok.Data;
@Data
public class NewsArticle {
/**
* 图文消息标题
* 必填
* 长度限制不超过128个字符
*/
private String title;
/**
* 图文消息描述
* 必填
* 长度限制不超过512个字符
*/
private String description;
/**
* 点击后跳转的链接
* 必填
* 格式要求包含协议头(http/https)
* 长度限制不超过2048字节
*/
private String url;
/**
* 图文消息配图的url
* 必填
* 长度限制不超过2048字节
*/
private String picurl;
}

View File

@ -0,0 +1,47 @@
package com.agileboot.domain.qywx.api.response;
import lombok.Data;
@Data
public class NewsMessageResponse {
/**
* 返回码
* 0表示成功非0表示失败
*/
private Integer errcode;
/**
* 错误信息
* 成功返回"ok"
*/
private String errmsg;
/**
* 不合法的userid列表
* 多个接收者用'|'分隔
*/
private String invaliduser;
/**
* 不合法的部门id列表
* 多个接收者用'|'分隔
*/
private String invalidparty;
/**
* 不合法的标签id列表
* 多个接收者用'|'分隔
*/
private String invalidtag;
/**
* 没有基础接口许可的userid列表
* 包含已过期的许可
*/
private String unlicenseduser;
/**
* 消息id
* 用于撤回应用消息72小时内有效
*/
private String msgid;
/**
* 响应代码
* 仅模板卡片消息返回用于更新消息72小时内有效
*/
private String response_code;
}

View File

@ -12,6 +12,8 @@ import com.agileboot.domain.shop.approval.model.ReturnApprovalModel;
import com.agileboot.domain.shop.approval.model.ReturnApprovalModelFactory; import com.agileboot.domain.shop.approval.model.ReturnApprovalModelFactory;
import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery; import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery;
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalQuery; import com.agileboot.domain.shop.approval.query.SearchReturnApprovalQuery;
import com.agileboot.domain.shop.goods.model.GoodsModel;
import com.agileboot.domain.shop.goods.model.GoodsModelFactory;
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity; import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
import com.agileboot.domain.shop.order.model.OrderGoodsModel; import com.agileboot.domain.shop.order.model.OrderGoodsModel;
import com.agileboot.domain.shop.order.model.OrderGoodsModelFactory; import com.agileboot.domain.shop.order.model.OrderGoodsModelFactory;
@ -45,6 +47,7 @@ public class ReturnApprovalApplicationService {
private final OrderGoodsModelFactory orderGoodsModelFactory; private final OrderGoodsModelFactory orderGoodsModelFactory;
private final OrderModelFactory orderModelFactory; private final OrderModelFactory orderModelFactory;
private final PaymentApplicationService paymentApplicationService; private final PaymentApplicationService paymentApplicationService;
private final GoodsModelFactory goodsModelFactory;
/** /**
* 获取退货审批列表 * 获取退货审批列表
@ -137,6 +140,7 @@ public class ReturnApprovalApplicationService {
} }
} }
// 更新审批状态为通过
model.validateApprovalStatus(); model.validateApprovalStatus();
model.setAuditImages(command.getAuditImages()); model.setAuditImages(command.getAuditImages());
model.setAuditRemark(command.getAuditRemark()); model.setAuditRemark(command.getAuditRemark());
@ -147,6 +151,11 @@ public class ReturnApprovalApplicationService {
// 更新关联订单商品状态 // 更新关联订单商品状态
orderGoodsModel.setStatus(2); // 6表示已完成退货 orderGoodsModel.setStatus(2); // 6表示已完成退货
orderGoodsModel.updateById(); orderGoodsModel.updateById();
// 更新商品库存
GoodsModel goodsModel = goodsModelFactory.loadById(orderGoodsModel.getGoodsId());
goodsModel.setStock(goodsModel.getStock() + orderGoodsModel.getQuantity());
goodsModel.updateById();
} }
/** /**

File diff suppressed because one or more lines are too long