mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-06-28 13:16:19 +08:00
🆕 #1746: 【企业微信】第三方应用增加授权配置接口,同时增加向员工付款的接口
This commit is contained in:
parent
c0af379370
commit
0e2186632a
@ -154,6 +154,20 @@ public interface WxCpTpService {
|
|||||||
*/
|
*/
|
||||||
String getPreAuthUrl(String redirectUri, String state) throws WxErrorException;
|
String getPreAuthUrl(String redirectUri, String state) throws WxErrorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 获取预授权链接,测试环境下使用
|
||||||
|
* @Link https://work.weixin.qq.com/api/doc/90001/90143/90602
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param redirectUri 授权完成后的回调网址
|
||||||
|
* @param state a-zA-Z0-9的参数值(不超过128个字节),用于第三方自行校验session,防止跨域攻击
|
||||||
|
* @param authType 授权类型:0 正式授权, 1 测试授权。
|
||||||
|
* @return pre auth url
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
String getPreAuthUrl(String redirectUri, String state, int authType) throws WxErrorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取企业的授权信息
|
* 获取企业的授权信息
|
||||||
*
|
*
|
||||||
@ -278,7 +292,7 @@ public interface WxCpTpService {
|
|||||||
* <pre>
|
* <pre>
|
||||||
* 获取访问用户敏感信息
|
* 获取访问用户敏感信息
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @param userTicket
|
* @param userTicket
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package me.chanjar.weixin.cp.tp.service.impl;
|
package me.chanjar.weixin.cp.tp.service.impl;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -210,6 +211,30 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ
|
|||||||
return preAuthUrl;
|
return preAuthUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public String getPreAuthUrl(String redirectUri, String state, int authType) throws WxErrorException {
|
||||||
|
String result = get(configStorage.getApiUrl(GET_PREAUTH_CODE), null);
|
||||||
|
WxCpTpPreauthCode preAuthCode = WxCpTpPreauthCode.fromJson(result);
|
||||||
|
String setSessionUrl = "https://qyapi.weixin.qq.com/cgi-bin/service/set_session_info";
|
||||||
|
|
||||||
|
Map<String,Object> sessionInfo = new HashMap<>(1);
|
||||||
|
sessionInfo.put("auth_type", authType);
|
||||||
|
Map<String,Object> param = new HashMap<>(2);
|
||||||
|
param.put("pre_auth_code", preAuthCode.getPreAuthCode());
|
||||||
|
param.put("session_info", sessionInfo);
|
||||||
|
String postData = new Gson().toJson(param);
|
||||||
|
|
||||||
|
post(setSessionUrl, postData);
|
||||||
|
|
||||||
|
String preAuthUrl = "https://open.work.weixin.qq.com/3rdapp/install?suite_id=" + configStorage.getSuiteId() +
|
||||||
|
"&pre_auth_code=" + preAuthCode.getPreAuthCode() + "&redirect_uri=" + URLEncoder.encode(redirectUri, "utf-8");
|
||||||
|
if (StringUtils.isNotBlank(state)) {
|
||||||
|
preAuthUrl += "&state=" + state;
|
||||||
|
}
|
||||||
|
return preAuthUrl;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WxCpTpAuthInfo getAuthInfo(String authCorpId, String permanentCode) throws WxErrorException {
|
public WxCpTpAuthInfo getAuthInfo(String authCorpId, String permanentCode) throws WxErrorException {
|
||||||
JsonObject jsonObject = new JsonObject();
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
@ -0,0 +1,229 @@
|
|||||||
|
package com.github.binarywang.wxpay.bean.entwxpay;
|
||||||
|
|
||||||
|
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
|
||||||
|
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||||
|
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||||
|
import lombok.*;
|
||||||
|
import me.chanjar.weixin.common.annotation.Required;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2020/11/29.
|
||||||
|
* 向员工付款请求对象
|
||||||
|
* @author 拎小壶冲
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Builder(builderMethodName = "newBuilder")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@XStreamAlias("xml")
|
||||||
|
public class EntWxEmpPayRequest extends BaseWxPayRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:商户订单号.
|
||||||
|
* 变量名:partner_trade_no
|
||||||
|
* 是否必填:是
|
||||||
|
* 示例值:10000098201411111234567890
|
||||||
|
* 类型:String
|
||||||
|
* 描述:商户订单号
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("partner_trade_no")
|
||||||
|
private String partnerTradeNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:需保持唯一性 用户openid.
|
||||||
|
* 变量名:openid
|
||||||
|
* 是否必填:是
|
||||||
|
* 示例值:oxTWIuGaIt6gTKsQRLau2M0yL16E
|
||||||
|
* 类型:String
|
||||||
|
* 描述:商户appid下,某用户的openid
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("openid")
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:设备号.
|
||||||
|
* 变量名:device_info
|
||||||
|
* 是否必填:否
|
||||||
|
* 示例值:13467007045764
|
||||||
|
* 类型:String(32)
|
||||||
|
* 描述:微信支付分配的终端设备号
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@XStreamAlias("device_info")
|
||||||
|
private String deviceInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:校验用户姓名选项.
|
||||||
|
* 变量名:check_name
|
||||||
|
* 是否必填:是
|
||||||
|
* 示例值:OPTION_CHECK
|
||||||
|
* 类型:String
|
||||||
|
* 描述:NO_CHECK:不校验真实姓名
|
||||||
|
* FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账)
|
||||||
|
* OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功)
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("check_name")
|
||||||
|
private String checkName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:收款用户姓名.
|
||||||
|
* 变量名:re_user_name
|
||||||
|
* 是否必填:可选
|
||||||
|
* 示例值:马花花
|
||||||
|
* 类型:String
|
||||||
|
* 描述:收款用户真实姓名。
|
||||||
|
* 如果check_name设置为FORCE_CHECK或OPTION_CHECK, 则必填用户真实姓名
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@XStreamAlias("re_user_name")
|
||||||
|
private String reUserName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:金额.
|
||||||
|
* 变量名:amount
|
||||||
|
* 是否必填:是
|
||||||
|
* 示例值:10099
|
||||||
|
* 类型:int
|
||||||
|
* 描述:企业付款金额, 单位为分
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("amount")
|
||||||
|
private Integer amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:企业付款描述信息.
|
||||||
|
* 变量名:desc
|
||||||
|
* 是否必填:是
|
||||||
|
* 示例值:理赔
|
||||||
|
* 类型:String
|
||||||
|
* 描述:企业付款操作说明信息。必填。
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("desc")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:Ip地址.
|
||||||
|
* 变量名:spbill_create_ip
|
||||||
|
* 是否必填:是
|
||||||
|
* 示例值:192.168.0.1
|
||||||
|
* 类型:String(32)
|
||||||
|
* 描述:调用接口的机器Ip地址
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("spbill_create_ip")
|
||||||
|
private String spbillCreateIp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名: 付款消息类型
|
||||||
|
* 变量名: ww_msg_type
|
||||||
|
* 是否必填: 是
|
||||||
|
* 示例值:NORMAL_MSG
|
||||||
|
* 描述:NORMAL_MSG:普通付款消息 APPROVAL _MSG:审批付款消息
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("ww_msg_type")
|
||||||
|
private String wwMsgType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名: 审批单号
|
||||||
|
* 变量名: approval_number
|
||||||
|
* 是否必填: 否
|
||||||
|
* 示例值: 201705160008
|
||||||
|
* 描述:ww_msg_type为APPROVAL _MSG时,需要填写approval_number
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@XStreamAlias("approval_number")
|
||||||
|
private String approvalNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名: 审批类型
|
||||||
|
* 变量名: approval_type
|
||||||
|
* 是否必填: 否
|
||||||
|
* 示例值: 1
|
||||||
|
* 描述:ww_msg_type为APPROVAL _MSG时,需要填写1
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@XStreamAlias("approval_type")
|
||||||
|
private Integer approvalType;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名: 项目名称
|
||||||
|
* 变量名: act_name
|
||||||
|
* 是否必填: 是
|
||||||
|
* 示例值: 产品部门报销
|
||||||
|
* 描述:项目名称,最长50个utf8字符
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Required
|
||||||
|
@XStreamAlias("act_name")
|
||||||
|
private String actName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名: 付款的应用id
|
||||||
|
* 变量名: agentid
|
||||||
|
* 是否必填: 否
|
||||||
|
* 示例值: 1
|
||||||
|
* 描述:以企业应用的名义付款,企业应用id,整型,可在企业微信管理端应用的设置页面查看。
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@XStreamAlias("agentid")
|
||||||
|
private Integer agentId;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkConstraints() throws WxPayException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isWxWorkSign() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void storeMap(Map<String, String> map) {
|
||||||
|
map.put("appid", appid);
|
||||||
|
map.put("mch_id", mchId);
|
||||||
|
map.put("device_info", deviceInfo);
|
||||||
|
map.put("partner_trade_no", partnerTradeNo);
|
||||||
|
map.put("openid", openid);
|
||||||
|
map.put("check_name", checkName);
|
||||||
|
map.put("re_user_name", reUserName);
|
||||||
|
map.put("amount", amount.toString());
|
||||||
|
map.put("desc", description);
|
||||||
|
map.put("spbill_create_ip", spbillCreateIp);
|
||||||
|
map.put("act_name", actName);
|
||||||
|
map.put("ww_msg_type", wwMsgType);
|
||||||
|
map.put("approval_number", approvalNumber);
|
||||||
|
map.put("approval_type", approvalType.toString());
|
||||||
|
map.put("agentid", agentId.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package com.github.binarywang.wxpay.service;
|
package com.github.binarywang.wxpay.service;
|
||||||
|
|
||||||
import com.github.binarywang.wxpay.bean.entpay.*;
|
import com.github.binarywang.wxpay.bean.entpay.*;
|
||||||
|
import com.github.binarywang.wxpay.bean.entwxpay.EntWxEmpPayRequest;
|
||||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,4 +144,15 @@ public interface EntPayService {
|
|||||||
* @throws WxPayException the wx pay exception
|
* @throws WxPayException the wx pay exception
|
||||||
*/
|
*/
|
||||||
EntPayRedpackQueryResult queryEnterpriseRedpack(EntPayRedpackQueryRequest request) throws WxPayException;
|
EntPayRedpackQueryResult queryEnterpriseRedpack(EntPayRedpackQueryRequest request) throws WxPayException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向员工付款
|
||||||
|
* 文档详见 https://work.weixin.qq.com/api/doc/90000/90135/90278
|
||||||
|
* 接口链接 https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/paywwsptrans2pocket
|
||||||
|
*
|
||||||
|
* @param request 请求对象
|
||||||
|
* @return EntPayResult the ent pay result
|
||||||
|
* @throws WxPayException the wx pay exception
|
||||||
|
*/
|
||||||
|
EntPayResult toEmpPay(EntWxEmpPayRequest request) throws WxPayException;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.github.binarywang.wxpay.service.impl;
|
package com.github.binarywang.wxpay.service.impl;
|
||||||
|
|
||||||
import com.github.binarywang.wxpay.bean.entpay.*;
|
import com.github.binarywang.wxpay.bean.entpay.*;
|
||||||
|
import com.github.binarywang.wxpay.bean.entwxpay.EntWxEmpPayRequest;
|
||||||
import com.github.binarywang.wxpay.bean.request.WxPayDefaultRequest;
|
import com.github.binarywang.wxpay.bean.request.WxPayDefaultRequest;
|
||||||
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
|
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
|
||||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||||
@ -151,6 +152,24 @@ public class EntPayServiceImpl implements EntPayService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntPayResult toEmpPay(EntWxEmpPayRequest request) throws WxPayException {
|
||||||
|
//企业微信签名,需要在请求签名之前
|
||||||
|
request.setNonceStr(String.valueOf(System.currentTimeMillis()));
|
||||||
|
request.setWorkWxSign(SignUtils.createEntSign(request.getAmount(), request.getAppid(), request.getDescription(),
|
||||||
|
request.getMchId(), request.getNonceStr(), request.getOpenid(), request.getPartnerTradeNo(),
|
||||||
|
request.getWwMsgType(), payService.getConfig().getEntPayKey(), WxPayConstants.SignType.MD5));
|
||||||
|
|
||||||
|
request.checkAndSign(this.payService.getConfig());
|
||||||
|
|
||||||
|
String url = this.payService.getPayBaseUrl() + "/mmpaymkttransfers/promotion/paywwsptrans2pocket";
|
||||||
|
String responseContent = this.payService.post(url, request.toXML(), true);
|
||||||
|
final EntPayResult result = BaseWxPayResult.fromXML(responseContent, EntPayResult.class);
|
||||||
|
|
||||||
|
result.checkResult(this.payService, request.getSignType(), true);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private String encryptRSA(File publicKeyFile, String srcString) throws WxPayException {
|
private String encryptRSA(File publicKeyFile, String srcString) throws WxPayException {
|
||||||
try {
|
try {
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
@ -127,6 +127,30 @@ public class SignUtils {
|
|||||||
sortedMap.put("total_amount", totalAmount + "");
|
sortedMap.put("total_amount", totalAmount + "");
|
||||||
sortedMap.put("wxappid", wxAppId);
|
sortedMap.put("wxappid", wxAppId);
|
||||||
|
|
||||||
|
return toSignBuilder(sortedMap, signKey, signType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信签名
|
||||||
|
* @param signType md5 目前接口要求使用的加密类型
|
||||||
|
*/
|
||||||
|
public static String createEntSign(Integer totalAmount, String appId, String description, String mchId,
|
||||||
|
String nonceStr, String openid, String partnerTradeNo, String wwMsgType,
|
||||||
|
String signKey, String signType) {
|
||||||
|
Map<String, String> sortedMap = new HashMap<>(8);
|
||||||
|
sortedMap.put("amount", String.valueOf(totalAmount));
|
||||||
|
sortedMap.put("appid", appId);
|
||||||
|
sortedMap.put("desc", description);
|
||||||
|
sortedMap.put("mch_id", mchId);
|
||||||
|
sortedMap.put("nonce_str", nonceStr);
|
||||||
|
sortedMap.put("openid", openid);
|
||||||
|
sortedMap.put("partner_trade_no", partnerTradeNo);
|
||||||
|
sortedMap.put("ww_msg_type", wwMsgType);
|
||||||
|
|
||||||
|
return toSignBuilder(sortedMap, signKey, signType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toSignBuilder(Map<String, String> sortedMap, String signKey, String signType) {
|
||||||
Iterator<Map.Entry<String, String>> iterator = new TreeMap<>(sortedMap).entrySet().iterator();
|
Iterator<Map.Entry<String, String>> iterator = new TreeMap<>(sortedMap).entrySet().iterator();
|
||||||
StringBuilder toSign = new StringBuilder();
|
StringBuilder toSign = new StringBuilder();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
@ -148,7 +172,6 @@ public class SignUtils {
|
|||||||
} else {
|
} else {
|
||||||
return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
|
return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user