您的位置:首页 > 移动开发 > 微信开发

使用golang快速开发微信公众平台(九):下载对账单

2017-07-11 15:52 866 查看
首先,对账单是csv格式的;其次,对账单不是非常标准非常标准的csv格式——你直接解析会挂掉。

所以我采用的方式为:把对账单分为2部分,先写第1部分,再把第2部分拼进去。

唉卧槽他大爷的微信。

package controllers

import (
"github.com/astaxie/beego"
"monkeyServer/shopUtils/RandomStrUtil"
"encoding/xml"
"strings"
"net/http"
"bytes"
"io/ioutil"
"fmt"
"os"
"encoding/csv"
"io"
"log"
)

type AdminWXBillsController struct {
beego.Controller
}

func (c *AdminWXBillsController) Post() {
c.EnableRender = false

//查询哪一天的对账单
date := c.GetString("wxDate", "")
if len(date) != 8 || date == "" {
c.Ctx.WriteString("日期参数长度错误")
}

//https://api.mch.weixin.qq.com/pay/downloadbill
//商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
//注意:
//1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致;
//2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
//3、对账单中涉及金额的字段单位为“元”。
//4、对账单接口只能下载三个月以内的账单。

//首先定义一个UnifyOrderReq用于填入我们要传入的参数。
type WXBillReq struct {
Appid     string `xml:"appid"`     //公众账号ID
Mch_id    string `xml:"mch_id"`    //商户号
Nonce_str string `xml:"nonce_str"` //随机字符串
Sign      string `xml:"sign"`      //签名
BillDate  string `xml:"bill_date"` //下载对账单的日期,格式:20140603
BillType  string `xml:"bill_type"` //ALL,返回当日所有订单信息,默认值 SUCCESS,返回当日成功支付的订单 REFUND,返回当日退款订单 RECHARGE_REFUND,返回当日充值退款订单(相比其他对账单多一栏“返还手续费”)
}

type WXBillResp struct {
Return_code string `xml:"return_code"`
Return_msg  string `xml:"return_msg"`
}

var yourReq WXBillReq
yourReq.Appid = beego.AppConfig.String("APPID")
yourReq.Mch_id = beego.AppConfig.String("Mchid")
yourReq.Nonce_str = RandomStrUtil.GetRandomString(32)
yourReq.BillDate = date
yourReq.BillType = "ALL"

var m map[string]interface{}
m = make(map[string]interface{}, 0)
m["appid"] = yourReq.Appid
m["mch_id"] = yourReq.Mch_id
m["nonce_str"] = yourReq.Nonce_str
m["bill_date"] = yourReq.BillDate
m["bill_type"] = yourReq.BillType
yourReq.Sign = wxpayCalcSign(m, WX_PAY_API_KEY) //这个key 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全

bytes_req, err := xml.Marshal(yourReq)
if err != nil {
beego.Error("wxpay转换为xml错误:", err)
return
}

str_req := strings.Replace(string(bytes_req), "UnifyOrderReq", "xml", -1)
//beego.Error("请求UnifiedOrder 拼接 xml 完成--------", str_req)

bytes_req = []byte(str_req)
//发送unified order请求.
req, err := http.NewRequest("POST", "https://api.mch.weixin.qq.com/pay/downloadbill", bytes.NewReader(bytes_req))
if err != nil {
beego.Error("New Http Request发生错误,原因:", err)
return
}
req.Header.Set("Accept", "application/xml")
//这里的http header的设置是必须设置的.
req.Header.Set("Content-Type", "application/xml;charset=utf-8")

client := http.Client{}
resp, _err := client.Do(req)
if _err != nil {
beego.Error("请求微信对账单接口发送错误, 原因:", _err)
return
}
beego.Error("请求微信对账单接口已经执行完成")

respBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
beego.Error("解析返回body错误", err)
return
}
defer resp.Body.Close()

xmlResp := WXBillResp{}
_err = xml.Unmarshal(respBytes, &xmlResp)

if xmlResp.Return_code == "FAIL" {
fmt.Printf("请求微信对账单失败 %+v\n:", xmlResp)
} else {

newPath := createWxBillCSVFile(date)

in := string(respBytes)
in = strings.Replace(in, "`", "", -1)

spliteAfter := strings.Split(in, "总交易单数")
r := csv.NewReader(strings.NewReader(spliteAfter[0]))

resultStr := make([][]string, 0)
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}

resultStr = append(resultStr, record)
}

//写入文件
f, err := os.Create(newPath)//创建文件
if err != nil {
beego.Error("创建csv文件错误", err)
}
defer f.Close()

w := csv.NewWriter(f)//创建一个新的写入文件流
err = w.WriteAll(resultStr)//写入数据
w.Flush()

//再读取文件 把因为分割缺少的文字补进来
r2 := csv.NewReader(strings.NewReader(strings.Replace(spliteAfter[1], ",总交易额", "总交易单数,总交易额", -1)))
resultStr2 := make([][]string, 0)
for {
record2, err := r2.Read()

if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}

resultStr2 = append(resultStr2, record2)
}

//写入剩下2行
w2 := csv.NewWriter(f)  //创建一个新的写入文件流
w2.WriteAll(resultStr2) //写入数据
w2.Flush()

c.Ctx.WriteString(string(respBytes))
}
}

func createWxBillCSVFile(date string) string {

dirPath := "static/wxcsv/"
if !IsFileExist(dirPath) {
err := os.MkdirAll(dirPath, 0)
beego.Error("创建csv文件夹存在错误 ", err)
}
newPath := dirPath + date + ".csv"
if IsFileExist(newPath) {
err := os.Remove(newPath)
if err != nil {
beego.Error("删除旧的csv文件错误", err)
}
}
return newPath
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  微信 golang csv
相关文章推荐