artisancloud / powerwechat Goto Github PK
View Code? Open in Web Editor NEWPowerWechat是一款基于WeChat SDK for Golang,支持小程序、微信支付、企业微信、公众号等全微信生态
Home Page: https://powerwechat.artisan-cloud.com
License: MIT License
PowerWechat是一款基于WeChat SDK for Golang,支持小程序、微信支付、企业微信、公众号等全微信生态
Home Page: https://powerwechat.artisan-cloud.com
License: MIT License
官方是提供
看了下源码,这一部分代代码 (src/payment/refund/client.go)
func (comp *Client) Refund(transactionID string, refundOutNO string, amount *power.HashMap, options *power.HashMap) (*response.ResponseRefund, error) {
result := &response.ResponseRefund{}
body := &object.HashMap{
"amount": amount,
}
if transactionID != "" {
(*body)["transaction_id"] = transactionID
} else if refundOutNO != "" {
(*body)["out_refund_no"] = refundOutNO
} else {
return nil, errors.New("please given transaction_id or out_refund_no. ")
}
body = object.MergeHashMap(body, options.ToHashMap())
endpoint := comp.Wrap("/v3/refund/domestic/refunds")
_, err := comp.PlainRequest(endpoint, nil, "POST", body, false, nil, result)
return result, err
}
#前提是修复该问题#44 (comment)
改为
/**
微信退款接口
transactionID string 微信支付订单号
outTradeNo string 商户订单号 (原接口未提供)
refundOutNO string 退款订单号(退款时生成)
amount *power.HashMap 退款金额相关信息
options *power.HashMap 备注相关信息
reason string 退款原因 (原接口未提供)
*/
func (comp *Client) Refund(transactionID string, outTradeNo string, refundOutNO string, reason string, amount *power.HashMap, options *power.HashMap) (*response.ResponseRefund, error) {
result := &response.ResponseRefund{}
body := &object.HashMap{
"amount": amount,
"reason": reason,
}
// 单方未空 取另一方有值
if transactionID == "" && outTradeNo != "" {
(*body)["out_trade_no"] = outTradeNo
}
if transactionID != "" && outTradeNo == "" {
(*body)["transaction_id"] = transactionID
}
// 两者皆有值优先取微信支付订单号
if transactionID != "" && outTradeNo != "" {
(*body)["transaction_id"] = transactionID
}
// 退款订单号是必须的 如果为空返回错误信息
if refundOutNO == "" {
return nil, errors.New("please make sure your refund_out_no field have value")
}else {
(*body)["out_refund_no"] = refundOutNO
}
// todo 校验为何数据未进入到body中
body = object.MergeHashMap(body, options.ToHashMap())
endpoint := comp.Wrap("/v3/refund/domestic/refunds")
_, err := comp.PlainRequest(endpoint, nil, "POST", body, false, nil, result)
return result, err
}
昨天直接使用官方文档 demo 直接 panic,改成 v2 版本才解决。
import "github.com/ArtisanCloud/PowerWeChat/src/work/message/request" // 需要改为 v2 版本
messages := &request.RequestMessageSendText{
RequestMessageSend: request.RequestMessageSend{
ToUser: "UserID1|UserID2|UserID3",
ToParty: "PartyID1|PartyID2",
ToTag: "TagID1 | TagID2",
MsgType: "text",
AgentID: 1,
Safe: 0,
EnableIDTrans: 0,
EnableDuplicateCheck: 0,
DuplicateCheckInterval: 1800,
},
Text: &request.RequestText{
Content: "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。",
},
}
WeComApp.Message.SendText(messages)
MiniProgramApp.PhoneNumber.GetUserPhoneNumber(code)
{
"errcode": 40001,
"errmsg": "invalid credential, access_token is invalid or not latest rid: 63763df8-7be20627-34978741"
}
调用退款接口
paymentClient, err := utils.NewWXPaymentApp(ctx.Request, params.AppId, NotifyUrl)
if err != nil {
panic(err)
}
fmt.Println(params.RefundOutNO)
// 1634095819-969073932
outRefundNo := fmt.Sprintf("%d-%d", time.Now().Unix(), time.Now().Nanosecond())
response, err := paymentClient.Refund.Refund("xxxxx", outRefundNo, &power.HashMap{
"refund": 15,
"total": 15,
"currency": "CNY",
}, &power.HashMap{
"reason": "技术部退款",
})
fmt.Println(response)
根据utils.NewWXPaymentApp()
方法中的HttpDebug: true
可看到请求参数缺失out_refund_no
以及api接口返回信息亦提示
输入源“/body/out_refund_no”映射到字段“商户退款单号”必填性规则校验失败,此字段为必填项
根据文档 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
此处结构体文件
http request error:json: cannot unmarshal array into Go struct field RefundPromotionDetail.promotion_detail.goods_detail of type struct { MerchantGoodsID string "json:\"merchant_goods_id\""; WechatPayGoodsID string "json:\"wechatpay_goods_id\""; GoodsName string "json:\"goods_name\""; UnitPrice int "json:\"unit_price\""; RefundAmount int "json:\"refund_amount\""; RefundQuantity int "json:\"refund_quantity\"" }
以下 JSON 是服务器返回的 JSON 样例:
{ "amount": { "currency": "CNY", "discount_refund": 700, "from": [], "payer_refund": 14200, "payer_total": 14200, "refund": 14900, "refund_fee": 80, "settlement_refund": 14900, "settlement_total": 14900, "total": 14900 }, "channel": "ORIGINAL", "create_time": "2022-12-08T14:08:15+08:00", "funds_account": "AVAILABLE", "out_refund_no": "ORDERNO123456", "out_trade_no": "ORDERNO123456", "promotion_detail": [ { "amount": 600, "goods_detail": [], "promotion_id": "39542421", "refund_amount": 600, "scope": "GLOBAL", "type": "COUPON" }, { "amount": 100, "goods_detail": [], "promotion_id": "3958275", "refund_amount": 100, "scope": "GLOBAL", "type": "COUPON" } ], "refund_id": "50302", "status": "SUCCESS", "success_time": "2022-12-08T14:08:24+08:00", "transaction_id": "420000159", "user_received_account": "xx银行借记卡1234" }
出于语言特性的原因,golang里面其他框架如果需要获得当前进程的请求参数,必须是使用者主动传递http.Request
。
同样,除了web框架之外的其他框架也不能直接响应数据给当次请求,除非使用者主动传递了ResponseWriter
进来。
这样导致目前闭包写法显得有点多余,里面判断了一次错误,然后外层还要再捕获一次再处理。
func CallbackWXNotify(c *gin.Context) {
_, err := services.PaymentApp.HandlePaidNotify(c.Request, func(message *power.HashMap, content *power.HashMap, fail string) interface{} {
if content == nil || (*content)["out_trade_no"] == nil {
return "no content notify"
}
// 看下支付通知事件状态
if (*message)["event_type"].(string) != services.TRANSACTION_SUCCESS {
// 这里可能是微信支付失败的通知,所以可能需要在数据库做一些记录,然后告诉微信我处理完成了。
return true
}
// 查询商户订单号
orderNO := (*content)["out_trade_no"].(string)
if orderNO != "" {
// 这里对照自有数据库里面的订单做查询以及支付状态改变
log.Printf("订单号:%s 支付成功", orderNO)
} else {
// 告诉微信我还没处理成功,等会它会重新发起通知
// 如果不需要,直接返回true即可
return "payment fail"
}
return true
})
if err != nil {
panic(err)
}
c.String(200, "")
}
如上图所示,回调里面的return string
表示是出错了,让微信等会重新发起请求, 接着又要在外层判断一次err != nil。
如果去掉闭包,可以直接在return string
的那一步就直接抛错,panic
或者c.Status(500)
都可以,所以建议大致重构成一下以下写法:
res, err := services.PaymentApp.HandlePaidNotify(c.Request)
if err != nil {
panic(err)
}
// 看下支付通知事件状态
if res.eventType != services.TRANSACTION_SUCCESS {
// 这里可能是微信支付失败的通知,所以可能需要在数据库做一些记录。
} else {
// 查询商户订单号
if res.OutTradeNo != "" {
// 这里对照自有数据库里面的订单做查询以及支付状态改变
log.Printf("订单号:%s 支付成功", res.OutTradeNo)
} else {
// 告诉微信我还没处理成功,等会它会重新发起通知
c.String(500, "通信失败,请稍后再通知我")
}
}
c.String(200, "")
我认为重构后的写法会更容易判断流更容易理解
在唤起微信支付时遇到错误返回时 会导致微信response无法读取的错误
希望在目标位置 src/kernel/response/wx.go
中的ResponsePayment结构体进行追加
type ResponsePayment struct {
ReturnCode string `json:"return_code"`
ReturnMSG string `json:"return_msg,omitempty"`
ResultCode string `json:"result_code"` // 是 String(16) SUCCESS/FAIL
ErrCode string `json:"err_code,omitempty"` // 否 String(32) SYSTEMERROR--系统错误
ErrMSG string `json:"errmsg,omitempty"`
ErrCodeDes string `json:"err_code_des,omitempty"`
Code string `json:"code,omitempty"` // 追加
Message string `json:"message,omitempty"` // 追加
}
POST /wxa/generate_urllink?access_token=62_qSoBD
HTTP/1.1
Content-Type: application/json
{
"cloud_base": null,
"env_version": "release",
"expire_interval": 1668158616,
"expire_type": 1,
"path": "pages/storedata/index",
"query": "FA=FAF\u0026mini_card_id=123"
}
{
"errcode": 40212,
"errmsg": "invalid query rid: 636e146b-3b26fb4a-11dfc7b4"
}
原始query:FA=FAF&mini_card_id=123
微信分帐回退功能 会加上码
看下了文档好像没有找到,大概什么时候上线这个功能呢
微信文档: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_8.shtml
因为申请交易账单和申请资金账单只是返回一个download_url
和hash
,所以需要再封装一个download接口。
希望能够实现特性:
参考特性:
paymentService.Bill.Download("your/path/to/file-2021-09-01.csv", &power.HashMap{
"download_url": "https://api.mch.weixin.qq.com/v3/billdownload/file?token=6XIv5TUPto7pByrTQKhd6kwvyKLG2uY2wMMR8cNXqaA_Cv_isgaUtBzp4QtiozLO",
"hash_type": "SHA1",
"hash_value": "8823044c286bea726f149bfcfce0b0318122d755",
})
基于上一个申请账单的数据,再下载可避免协程之间并发导致的数据冲突。
由于微信小程序直播部分存在文档缺陷,所有接口都是相同的传参和返回值。
例如:
等页面中,文档都是一样的,只是api名字换了一下。
微信的直播文档在平台能力那边,所以需要重新根据小程序直播里面的文档重新封装sdk。
// 下单
response, err := paymentService.Order.JSAPITransaction(&object.HashMap{
"amount": &object.HashMap{
"total": 1,
"currency": "CNY",
},
"attach": "自定义数据说明",
"description": "Image形象店-深圳腾大-QQ公仔",
"mchid": "1611854986",
"notify_url": "https://pay.wangchaoyi.com/wx/notify",
"out_trade_no": "5519778939773395659222199398", // 这里是商户订单号,不能重复提交给微信
"payer": &object.HashMap{
"openid": "oAuaP0TRUMwP169nQfg7XCEAw3HQ", // 用户的openid, 记得也是动态的。
},
}, false)
if err != nil {
log.Printf("error: %s", err)
c.JSON(400, response)
return
}
payConf, err := paymentService.JSSDK.BridgeConfig(response.PrepayID, true)
if err != nil {
panic(err)
}
c.JSON(200, payConf)
请看以上示例代码, 如果在第一步Order.JSAPITransaction
步骤,提交给微信的参数有问题。
例如:
这些微信已经明显抛错的地方,我认为应该是在第一次的err
里面需要被自动捕获的。不然目前就存在一个很尴尬的行为,就是明明微信已经提示商户订单号重复
,结果后面的JSSDK.BridgeConfig
还是拿着空PrepayID
去生成签名,最终导致微信前端支付出错。
目前临时补救的行为是在第一次判断err != nil
的时候,再加上一个err != nil || response.PrepayID != ""
,但我觉得这个会增加使用者的心智负担,使用者不可能记住每个API的额外的判断错误条件,这个预下单的接口是response.PrepayID != ""
,另外一个可能还是response.ErrCode != 0
,最终会导致遗漏判断影响后续的业务流程。
请参考以下php示例代码,如果服务端返回了500,最后会进入catch流程,这个是更符合我们的编程直觉的。
try {
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'http://httpbin.org/status/500');
echo $response->getStatusCode(); // 200
echo $response->getHeaderLine('content-type'); // 'application/json; charset=utf8'
echo $response->getBody(); // '{"id": 1420053, "name": "guzzle", ...}'
} catch (Exception $exception) {
dump("出错了");
dd($exception);
}
所以我认为应该参考php guzzle的做法,对于4xx
和5xx
的行为做一次err捕获,让用户只判断一个err != nil
就可以开始处理错误,至于是系统级错误或者是业务错误,再让使用者在里面进行判断。
Best Wish!
在发布微信菜单,url中含有了&符号,会被转义为\u0026,导致发布失败;
{
"errcode": 40033,
"errmsg": "invalid charset. please check your request, if include \uxxxx will create fail! rid: 6351f0e3-4fa90897-25a38569"
}
然后用http.Post原始的请求发布,并没有这种问题,通过调试,发现是因为请求中json编码后会有这个问题存在。
感谢官方提供这么好用的库。也希望能解决这个bug
不过官方的企微bot文档很不完善,只有每个bot点进去那一页,讲推送消息的方法…
接收消息基本没文档
比如message_type除了text和mixed,还能为event,此时event.event_type可能为:
全网找不到,这俩还是自己试出来的
WeComApp.Server.Notify()接收企微审批状态变更回调消息解析出来的数据是空的
`rs, err := pwWechat.WeComApp.Server.Notify(c.Request, func(event contract.EventInterface) interface{} {
fmt.Dump("event", event)
// kernel.Encryptor(event)
msg := models1.EventOpenApprovalChange{}
err := event.ReadMessage(&msg)
if err != nil {
println(err.Error())
return "error"
}
fmt.Dump(msg)
return kernel.SUCCESS_EMPTY_RESPONSE
})`
{ "EventInterface": null, "XMLName": { "Space": "", "Local": "" }, "Text": "", "ToUserName": "ww674ab0ba94f03533", "FromUserName": "sys", "CreateTime": "1659066539", "MsgType": "event", "Event": "sys_approval_change", "ChangeType": "", "Content": null, "AgentID": "3010040", "ApprovalInfo": { "Text": "", "ThirdNo": "", "OpenSpName": "", "OpenTemplateID": "", "OpenSpStatus": "", "ApplyTime": "1658900033", "ApplyUserName": "", "ApplyUserID": "", "ApplyUserParty": "", "ApplyUserImage": "", "ApprovalNodes": { "Text": "", "ApprovalNode": { "Text": "", "NodeStatus": "", "NodeAttr": "", "NodeType": "", "Items": { "Text": "", "Item": { "Text": "", "ItemName": "", "ItemUserID": "", "ItemImage": "", "ItemStatus": "", "ItemSpeech": "", "ItemOpTime": "" } } } }, "NotifyNodes": { "Text": "", "NotifyNode": { "Text": "", "ItemName": "", "ItemUserID": "", "ItemImage": "" } }, "Approverstep": "" } }
看了下代码,有重试刷新token机制,如果并发,是不是会重复顶掉之前的token(第一次拿token并发也会出现)。能否抽象Acess_token,调用方自己实现逻辑。
类似下面的代码
type AccessToken interface {
GetAccessToken() (accessToken string, err error)
RefreshAccessToken(accessToken string) (accessToken string, err error)
}
检测到 ArtisanCloud/PowerWeChat 一共引入了59个开源组件,存在1个漏洞
漏洞标题:Gin-Gonic Gin 环境问题漏洞
缺陷组件:github.com/gin-gonic/[email protected]
漏洞编号:CVE-2020-28483
漏洞描述:Gin-Gonic Gin是Gin-Gonic团队的一个基于Go语言的用于快速构建Web应用的框架。
github.com/gin-gonic/gin 全部版本存在安全漏洞,该漏洞源于可以通过设置X-Forwarded-For头来欺骗客户端的IP。
影响范围:(∞, 1.7.7)
最小修复版本:1.7.7
缺陷组件引入路径:github.com/ArtisanCloud/PowerWeChat@->github.com/gin-gonic/[email protected]
另外还有几个漏洞,详细报告:https://mofeisec.com/jr?p=a1996d
小程序本身接口是支持部分特殊字符的"最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)"
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html#method-http.
但是WXACode.GetUnlimited中scene传参带特殊字符,调用微信接口时会被转义导致微信报40129错误
好像没看到微信公众号取消关注事件的定义unsubscribe;
const (
CALLBACK_EVENT_SUBSCRIBE = "subscribe"
CALLBACK_EVENT_ENTER_AGENT = "enter_agent"
CALLBACK_EVENT_LOCATION = "LOCATION"
CALLBACK_EVENT_BATCH_JOB_RESULT = "batch_job_result"
CALLBACK_EVENT_CLICK = "click"
CALLBACK_EVENT_VIEW = "view"
CALLBACK_EVENT_SCANCODE_PUSH = "scancode_push"
CALLBACK_EVENT_SCANCODE_WAITMSG = "scancode_waitmsg"
CALLBACK_EVENT_PIC_SYSPHOTO = "pic_sysphoto"
CALLBACK_EVENT_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"
CALLBACK_EVENT_PIC_WEIXIN = "pic_weixin"
CALLBACK_EVENT_LOCATION_SELECT = "location_select"
CALLBACK_EVENT_OPEN_APPROVAL_CHANGE = "open_approval_change"
CALLBACK_EVENT_SHARE_AGENT_CHANGE = "share_agent_change"
CALLBACK_EVENT_TEMPLATE_CARD_MENU_EVENT = "template_card_menu_event"
)
逛了一圈,只有powerwechat的文档最清晰,赞一个!
期望增加企微上传文件接口。
上传方法缺失的话,只能发送文本消息,很多send方法都不能用。
问题产生:在微信公众号中开启安全模式(明文模式没问题)
结果:服务器输出的xml为加密格式,微信无法正确识别
代码位置:serverGuard.go 382行
`if serverGuard.IsSafeMode(request) {
// tbd log here
encryptor := (*serverGuard.App).GetComponent("Encryptor").(*Encryptor)
encryptedResponse, err := encryptor.Encrypt(response, "", "")
if err == nil {
response = string(encryptedResponse)
} else {
// tbd log here
println("encryptor error: ", err.ErrMsg)
}
}`
当把这个注释时,安全模式可以正常返回消息
user, err := WeComApp.OAuth.Provider.ContactFromCode(code)
, user.GetID()
可以正确返回值。但是如果使用详细版user, err := WeComApp.OAuth.Provider.Detailed().ContactFromCode(code)
,里面user.GetID()
获取到的为空。user.GetRaw()
会抛错interface {} is object.HashMap, not *object.HashMap
。GetAuthURL()
之前需要全局设置WithRedirectURL(callbackUrl)
,这个在网络请求存在并发的情况下可能导致callbackUrl冲突。redirect_uri
需要被urlencode编码,不然在一些带有特殊字符的情况下导致OAuth2重定向调整出错。oa.Client.ApprovalTemplate() 返回的response中的 TemplateContent为JsonObject, []*power.HashMap无法解析, 改为*power.HashMap解析成功
http request error:json: cannot unmarshal object into Go struct field ResponseApprovalTemplate.template_content of type []*power.HashMap
{
"errcode": 0,
"errmsg": "ok",
"template_content": {
"controls": [
...
]
},
"template_names": [
...
]
}
```
请问是否支持小程序新版获取手机号
type Button struct {
Type string json:"type,omitempty"
Name string json:"name"
Key string json:"key,omitempty"
SubButtons []SubButton json:"sub_button,omitempty"
}
因为没有url,导致发布菜单时被提示button url size ;不用库的这种方式接收数据,通过http.Post组装数据发送一切正常。
type Button struct {
Type string json:"type,omitempty"
Name string json:"name"
Key string json:"key,omitempty"
URL string json:"url,omitempty"
#添加这个后,发布菜单成功
SubButtons []SubButton json:"sub_button,omitempty"
}
因为小程序的直播传参里面需要的media id依赖于素材管理,而小程序服务端API本身没有这个功能,需要使用到微信公众号的素材管理,所以公众号的素材管理功能需要前置。
相关文档链接: https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html
MiniProgramApp.Auth.Session 返回的errcode不存在 直接通过err判断不了 errcode不为0的情况
session, err := s.MiniProgramApp.Auth.Session(ctx.Request.Context(), reqParams.Code)
if err != nil {
return nil, err
}
if session.ErrCode != 0 {
return nil, errors.New(session.ErrMsg)
}
session.ErrCode 判断报错 请问怎么解决啊?
微信支付v3 api对请求方法有强制要求,如两个查询订单接口,微信接口要求使用GET方法
当前client中使用POST发起查询,微信返回405 Method not allowed
使用官方 demo,验证企业微信应用回调,总是返回 success(简单 curl 一下也是),(企业微信官方应该是要原文返回)
demo:
PowerWeChat 版本:v2.0.1-beta8
看起来是 bug,也有可能我使用的姿势不对?
还望解答一下,感谢 @Matrix-X @EveCoffee
V3增加了context,可以通过context来控制timeout超时请求后,强制取消该词业务请求
// ------ 比如 强制取消获取部门列表接口 ------
ctx,cancel := context.WithTimeout(context.Background(), 1*time.Second)
dept,err := wechatWork.Department.List(ctx, id)
// ------ PowerLib中的单元测试 ------
func TestDataflow_WithContext(t *testing.T) {
df := InitBaseDataflow()
ctx, cancel := context.WithCancel(context.Background())
done := make(chan struct{}, 1)
go func() {
time.Sleep(time.Second * 1)
_, err := df.WithContext(ctx).Request()
if !errors.Is(err, context.Canceled) {
t.Error("cancel failed")
}
done <- struct{}{}
}()
cancel()
select {
case <-done:
}
}
这个是由于Token和AESKey没有配置导致的,这个在公众号、企业微信配置里面都有这个参数,用来消息回调解密用。如果暂时不用消息解密,随便设置一个字符串进去即可。
例如:
officialAccount.NewOfficialAccount(&officialAccount.UserConfig{
AppID: conf.OffiAccount.AppID, // 小程序、公众号或者企业微信的appid
Secret: conf.OffiAccount.AppSecret, // 商户号 appID
Token: "xxx",
AESKey: "xxx",
ResponseType: os.Getenv("response_type"),
Log: officialAccount.Log{
Level: "debug",
File: "./wechat.log",
},
Cache: cache,
HttpDebug: true,
Debug: false,
//"sandbox": true,
})
Question:
调用 Transfer.QueryBalanceOrder 查询抛出异常,代码为:
panic: reflect: call of reflect.Value.IsNil on bool value
问题原因: 企业微信里面每次发送消息是需要agentid
的。
解决方案: sdk里面可以判断如果用户没有填充agentid
,那就走初始化时候的agentid
。
微信文档地址: https://open.work.weixin.qq.com/api/doc/90000/90135/90236
paymentService.Refund.Refund(
transactionID, // 微信支付单号
refundOutNO, // 商户外部单号
&object.HashMap{
"refund": 1, // 退款金额。 必填
"total": 1, // 总金额。 必填
"currency": "CNY", // 目前微信只支持CNY
},
nil,
)
refundOutNO应为自己生成的退款单号 而不是商户下单号
jssdk退款文档
如图,红框部分没有进去。预期能在err中捕获到错误然后阻止后面的逻辑,结果是到了c.JSON(200, rs)
。
sdk提交给微信的参数多了appid和mchid,导致微信报错
{
"amount": {
"currency": "CNY",
"refund": 1,
"total": 1
},
"appid": "ww16143ea0101327cc",
"mchid": "1611854988",
"out_refund_no": "551977893977339565922219",
"transaction_id": "4200001207202108286046087111"
}
微信支付退款 返回结果:
{
"code": "PARAM_ERROR",
"detail": {
"location": null,
"value": [
"/body/appid",
"/body/mchid"
]
},
"message": "请求中含有未在API文档中定义的参数"
}
我用.OAuth.UserFromCode可以成功调用,但是当我用对应的GetAccessToken,或者getopenid都获取不到对应的值
接口版本:v2
当前时间(2022-07-29)默认go get下来的库为[email protected]
镜像仓库为goproxy.cn
此版本库accessToken.go:46:16 baseClient.go:38:16位置存在错误,双返回的request.NewHttpRequest(config)方法只取了一个值
非常感谢 ArtisanCloud 团队开发的 PowerWeChat,我有以下一个问题想咨询?
在微信支付中,为什么分账接收方的 Receivers
参数的类型不是切片?
p.payment.ProfitSharing.Share(&request.RequestShare{
AppID: "",
TransactionID: "",
OutOrderNO: "",
Receivers: &request.Receivers{}, // 为什么分账接收方的Receivers类型不是切片?
UnfreezeUnSplit: true
})
我看文档指向路径好像并不是v3
powerWechat是做的老版微信支付接口吗
考虑v3吗 ?
最近微信支付又有了一些改动, 例 企业付款到零钱关闭新商户开通了
`// 本接口提供基于小程序的条码/二维码识别的API
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/img/img.scanQRCode.html
func (comp *Client) ScanQRCode(imgURL string, img *power.HashMap) (*response.ResponseIMGScanQRCode, error) {
result := &response.ResponseIMGScanQRCode{}
_, err := comp.UploadImage("cv/img/aicrop", imgURL, img, result)
return result, err
}`
url应该是 'cv/img/qrcode'
因为微信的access_token只允许一个,如果获取了新的token,上一个会在5分钟左右失效。但是目前sdk没有自动刷新机制,导致提前失效之后除非重启应用,否则不会重新刷新。
参考token失效的错误:
{
"errcode": 40001,
"errmsg": "invalid credential, access_token is invalid or not latest rid: 6141b79a-7c6e812d-5514c622",
"resultcode": "",
"resultmsg": ""
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.