package controllers
import (
"XT_New/enums"
"XT_New/models"
"XT_New/service"
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"github.com/astaxie/beego"
"io/ioutil"
"math/rand"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
"time"
)
const (
pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
)
type PayApiController struct {
BaseServeAPIController
parameters map[string]string
resultParameters map[string]string
payUrl string
}
type PayApiController2 struct {
beego.Controller
parameters map[string]string
resultParameters map[string]string
payUrl string
}
func PayApiRegistRouters() {
beego.Router("/api/my/service", &PayApiController{}, "Get:GetMyService")
beego.Router("/api/product", &PayApiController{}, "Get:GetProduct")
beego.Router("/api/pay", &PayApiController{}, "Get:GetPayUrl")
beego.Router("/api/pay/transfer", &PayApiController{}, "Post:PostTransferStatus")
beego.Router("/api/order", &PayApiController{}, "Post:PostOrderInfo")
beego.Router("/api/order/get", &PayApiController{}, "Get:GetOrderInfo")
beego.Router("/api/pay/notify", &PayApiController2{}, "Post:WxPaySuccessNotify")
beego.Router("/api/order/cancel", &PayApiController{}, "Post:CancelOrder")
beego.Router("/api/order/list", &PayApiController{}, "Get:GetOrderList")
beego.Router("/api/order/hetong", &PayApiController{}, "Get:GetHeTong")
beego.Router("/api/order/hetong", &PayApiController{}, "Post:CreateHeTong")
}
func (c *PayApiController) GetOrderList() {
adminUserInfo := c.GetAdminUserInfo()
serviceOrderList, err := service.GetOrderList(adminUserInfo.CurrentOrgId)
if err == nil {
c.ServeSuccessJSON(map[string]interface{}{
"list": serviceOrderList,
})
} else {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
}
}
func (c *PayApiController) CancelOrder() {
adminUserInfo := c.GetAdminUserInfo()
orderId, _ := c.GetInt64("id", 0)
if orderId == 0 {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
return
}
order, err := service.FindServeOrderByID(adminUserInfo.CurrentOrgId, orderId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if order == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
return
}
errs := service.UpdateOrderStatus(adminUserInfo.CurrentOrgId, orderId)
if errs == nil {
c.ServeSuccessJSON(map[string]interface{}{
"msg": "取消成功",
})
} else {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
}
}
func (c *PayApiController) PostTransferStatus() {
adminUserInfo := c.GetAdminUserInfo()
orderId, _ := c.GetInt64("id", 0)
if orderId == 0 {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
return
}
order, err := service.FindServeOrderByID(adminUserInfo.CurrentOrgId, orderId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if order == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
return
}
errs := service.UpdateOrderPayType(adminUserInfo.CurrentOrgId, orderId)
if errs == nil {
c.ServeSuccessJSON(map[string]interface{}{
"msg": "确认成功",
})
} else {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
}
}
func (c *PayApiController) GetOrderInfo() {
adminUserInfo := c.GetAdminUserInfo()
orderId, _ := c.GetInt64("id", 0)
order, err := service.FindServeOrderByID(adminUserInfo.CurrentOrgId, orderId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if order == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
return
}
orderInfo, err := service.FindOrderInfomationByID(order.OrderNumber, adminUserInfo.CurrentOrgId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if orderInfo == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
return
}
c.ServeSuccessJSON(map[string]interface{}{
"total": order.PaymentAmount,
"orderNumber": order.OrderNumber,
"OrgName": adminUserInfo.Orgs[adminUserInfo.CurrentOrgId].OrgName,
"order": order,
"orderInfo": orderInfo,
})
}
func (c *PayApiController) PostOrderInfo() {
adminUserInfo := c.GetAdminUserInfo()
amount, _ := c.GetInt64("amount", 0)
productId, _ := c.GetInt64("id", 0)
product, err := service.FindProductByID(productId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if product == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeProductError)
return
}
timestamp := c.GetTimestamp()
//自定义订单号
bill_no := "S" + strconv.FormatInt(timestamp, 10) + strconv.FormatInt(adminUserInfo.CurrentOrgId, 10)
order := models.ServeOrder{
OrgId: adminUserInfo.CurrentOrgId,
Period: amount * 12,
Status: 1,
CreatedTime: time.Now().Unix(),
UpdatedTime: time.Now().Unix(),
OrderNumber: bill_no,
OrderStatus: 1,
PayableAmount: float64(amount) * product.Price,
PaymentAmount: float64(amount) * product.Price,
ServeName: product.ServeName,
ServeDesc: product.ServeDesc,
OrderExpireTime: time.Now().Unix() + (7 * 24 * 3600),
Quantity: amount,
Price: product.Price,
ServeId: productId,
}
infomation := models.ServeOrderInfomation{
OrgId: adminUserInfo.CurrentOrgId,
OrderNumber: bill_no,
Status: 1,
ProductId: product.ID,
ProductName: product.ServeName,
ProductDesc: product.ServeDesc,
Price: product.Price,
Quantity: amount,
MarketPrice: product.OriginalPrice,
}
service.CreateOrderRecord(&order)
service.CreateOrderInfomation(&infomation)
c.ServeSuccessJSON(map[string]interface{}{
"order": order,
"msg": "提交订单成功",
})
}
func (c *PayApiController) GetProduct() {
adminUserInfo := c.GetAdminUserInfo()
products, err := service.FindAllProduct()
subscibe, _ := service.FindServiceSubscibeByOrgId(adminUserInfo.CurrentOrgId)
if err == nil {
c.ServeSuccessJSON(map[string]interface{}{
"products": products,
"subscibe": subscibe,
"serviceTime": time.Now().Unix(),
//"OrgName": adminUserInfo.Orgs[adminUserInfo.CurrentOrgId].OrgName,
})
} else {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeSystemError)
}
}
func (c *PayApiController) GetMyService() {
adminUserInfo := c.GetAdminUserInfo()
subscibe, err := service.FindServiceSubscibeByOrgId(adminUserInfo.CurrentOrgId)
if err == nil {
c.ServeSuccessJSON(map[string]interface{}{
"subscibe": subscibe,
"serviceTime": time.Now().Unix(),
})
} else {
}
}
func (c *PayApiController) GetPayUrl() {
adminUserInfo := c.GetAdminUserInfo()
orderId, _ := c.GetInt64("id", 0)
if orderId == 0 {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
return
}
order, err := service.FindServeOrderByID(adminUserInfo.CurrentOrgId, orderId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if order == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
return
}
orderInfo, err := service.FindOrderInfomationByID(order.OrderNumber, adminUserInfo.CurrentOrgId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if orderInfo == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
return
}
totalPrice := orderInfo.Price * float64(orderInfo.Quantity)
totalFee := fmt.Sprintf("%.0f", totalPrice*100)
c.SetParameter("out_trade_no", orderInfo.OrderNumber)
c.SetParameter("total_fee", totalFee)
c.SetParameter("trade_type", "NATIVE")
c.SetParameter("body", order.ServeName)
notify_url := beego.AppConfig.String("httpdomain") + "/api/pay/notify"
c.SetParameter("product_id", orderInfo.OrderNumber)
c.SetParameter("notify_url", notify_url)
c.SetParameter("spbill_create_ip", c.GetClientIp())
fmt.Println(c.GetClientIp())
url, err := c.GetPayCodeUrl()
fmt.Println(err)
if err == nil {
c.SetPayUrl(url)
c.ServeSuccessJSON(map[string]interface{}{
"payUrl": url,
"price": order.PayableAmount,
//": adminUserInfo.Orgs[adminUserInfo.CurrentOrgId].OrgName,
})
} else {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
// utils.LogError(err)
}
}
func (this *PayApiController2) WxPaySuccessNotify() {
type PaySuccessXmlResp struct {
ReturnCode string `xml:"return_code"`
Appid string `xml:"appid"`
BankType string `xml:"bank_type"`
CashFee int64 `xml:"cash_fee"`
FeeType string `xml:"fee_type"`
IsSubscribe string `xml:"is_subscribe"`
MchId string `xml:"mch_id"`
NonceStr string `xml:"nonce_str"`
OpenId string `xml:"openid"`
OutTradeNo string `xml:"out_trade_no"`
ResultCode string `xml:"result_code"`
Sign string `xml:"sign"`
TimeEnd string `xml:"time_end"`
TotalFee string `xml:"total_fee"`
TradeType string `xml:"trade_type"`
TransactionId string `xml:"transaction_id"`
}
defer this.Ctx.Request.Body.Close()
result, _ := ioutil.ReadAll(this.Ctx.Request.Body)
res := new(PaySuccessXmlResp)
xmlErr := xml.Unmarshal(result, &res)
if xmlErr != nil {
}
order, _ := service.FindServeOrderByOrderNumber(res.OutTradeNo)
service.UpdateOrder(order.OrderNumber, order.Quantity, order.OrgId, res.TransactionId, order.PeriodEnd, order.PeriodStart)
this.SetResultParameter("return_code", res.ReturnCode)
results := this.ParamsToXml2(this.resultParameters)
this.Ctx.WriteString(results)
this.ServeXML()
}
func (this *PayApiController) GetTimestamp() int64 {
return time.Now().UnixNano() / 1000000 //毫秒
}
func (this *PayApiController) GetClientIp() string {
ip := this.Ctx.Request.Header.Get("Remote_addr")
if ip == "" {
ip = this.Ctx.Request.RemoteAddr
}
if strings.Contains(ip, ":") {
ip = this.Substr(ip, 0, strings.Index(ip, ":"))
}
return ip
}
// 截取字符串 start 起点下标 end 终点下标(不包括)
func (this *PayApiController) Substr(str string, start int, end int) string {
rs := []rune(str)
length := len(rs)
if start < 0 || start > length {
return ""
}
if end < 0 || end > length {
return ""
}
return string(rs[start:end])
}
// 设置请求参数
func (this *PayApiController) SetParameter(key string, value string) {
if this.parameters == nil {
this.parameters = make(map[string]string)
}
this.parameters[key] = value
}
// 设置请求参数
func (this *PayApiController2) SetResultParameter(key string, value string) {
if this.resultParameters == nil {
this.resultParameters = make(map[string]string)
}
this.resultParameters[key] = value
}
// 设置prepay_id
func (this *PayApiController) SetPayUrl(payUrl string) {
this.payUrl = payUrl
}
type XmlResp struct {
Return_code string `xml:"return_code"`
Return_msg string `xml:"return_msg"`
Result_code string `xml:"result_code"`
Err_code string `xml:"err_code"`
Err_code_des string `xml:"err_code_des"`
Prepay_id string `xml:"prepay_id"`
Code_url string `xml:"code_url"`
}
func (this *PayApiController) GetPayCodeUrl() (string, error) {
strXml, err := this.CreateXml()
if err != nil {
return "", this.Error("get pay_code_url error", err)
}
result, err := this.http_post(pay_url, strXml)
if err != nil {
return "", this.Error("get pay_code_url error", err)
}
res := new(XmlResp)
xmlErr := xml.Unmarshal(result, &res)
if xmlErr != nil {
return "", this.Error("get pay_code_url xml error", xmlErr)
}
if res.Return_code != "SUCCESS" {
return "", this.Error("get pay_code_url result error: "+res.Return_msg, nil)
}
if res.Result_code != "SUCCESS" {
return "", this.Error("get pay_code_url result error: "+res.Err_code+"-"+res.Err_code_des, nil)
}
if res.Code_url == "" {
return "", this.Error("get pay_code_url result error: not get pay_code_url", nil)
}
return res.Code_url, nil
}
func (this *PayApiController) http_post(url string, xml string) ([]byte, error) {
bc := &http.Client{
Timeout: 30 * time.Second, //设置超时时间30s
}
res, err := bc.Post(url, "text/xml:charset=UTF-8", strings.NewReader(xml))
if err != nil {
return nil, this.Error("post", err)
}
result, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
return nil, this.Error("post result err", err)
}
return result, nil
}
func (this *PayApiController) CreateXml() (string, error) {
//检测必填参数
if this.parameters["out_trade_no"] == "" {
return "", this.Error("缺少统一支付接口必填参数out_trade_no(商户订单号)!", nil)
} else if this.parameters["body"] == "" {
return "", this.Error("缺少统一支付接口必填参数body(商品描述)!", nil)
} else if this.parameters["total_fee"] == "" {
return "", this.Error("缺少统一支付接口必填参数total_fee(交易金额)!", nil)
} else if this.parameters["notify_url"] == "" {
return "", this.Error("缺少统一支付接口必填参数notify_url(异步接收微信支付结果通知的回调地址)!", nil)
} else if this.parameters["trade_type"] == "" {
return "", this.Error("缺少统一支付接口必填参数trade_type(交易类型)!", nil)
} else if this.parameters["spbill_create_ip"] == "" {
return "", this.Error("缺少统一支付接口必填参数spbill_create_ip(终端ip)", nil)
} else if this.parameters["trade_type"] == "NATIVE" && this.parameters["product_id"] == "" {
return "", this.Error("统一支付接口中,缺少必填参数product_id!trade_type为NATIVE时,product_id为必填参数!", nil)
}
this.parameters["appid"] = beego.AppConfig.String("appid") //公众账号ID
this.parameters["mch_id"] = beego.AppConfig.String("mchid") //商户号
this.parameters["nonce_str"] = this.CreateNoncestr(32) //随机字符串
this.parameters["sign"] = this.GetSign(this.parameters, beego.AppConfig.String("key")) //签名
return this.ParamsToXml(this.parameters), nil
}
// 产生随机字符串,不长于32位
func (this *PayApiController) CreateNoncestr(length int) (nonceStr string) {
chars := "abcdefghijklmnopqrstuvwxyz0123456789"
for i := 0; i < length; i++ {
idx := rand.Intn(len(chars) - 1)
nonceStr += chars[idx : idx+1]
}
return
}
func (this *PayApiController) Error(strMsg string, err error) error {
if err == nil {
return errors.New(strMsg)
} else {
return errors.New(strMsg + ": " + err.Error())
}
}
// 格式化参数,签名过程需要使用
func (this *PayApiController) FormatParams(paramsMap map[string]string) string {
//STEP 1, 对key进行升序排序.
var sorted_keys []string
for k, _ := range paramsMap {
sorted_keys = append(sorted_keys, k)
}
sort.Strings(sorted_keys)
//STEP2, 对key=value的键值对用&连接起来,略过空值
var paramsStr []string
for _, k := range sorted_keys {
v := fmt.Sprintf("%v", strings.TrimSpace(paramsMap[k]))
if v != "" {
paramsStr = append(paramsStr, fmt.Sprintf("%s=%s", k, v))
}
}
return strings.Join(paramsStr, "&")
}
// 生成签名
func (this *PayApiController) GetSign(paramsMap map[string]string, wxKey string) string {
//STEP 1:按字典序排序参数
paramsStr := this.FormatParams(paramsMap)
//STEP 2:在string后加入KEY
signStr := paramsStr + "&key=" + wxKey
//STEP 3:MD5加密
sign := md5.New()
sign.Write([]byte(signStr))
//STEP 3:所有字符转为大写
return strings.ToUpper(hex.EncodeToString(sign.Sum(nil)))
}
// xml结构
func (this *PayApiController) ParamsToXml(data map[string]string) string {
fmt.Println(data)
buf := bytes.NewBufferString("")
for k, v := range data {
str := ""
flag, _ := regexp.MatchString("^\\d+\\.?\\d*$", v)
if flag {
str = "%s"
}
buf.WriteString(fmt.Sprintf("<%s>"+str+"%s>", k, v, k))
}
buf.WriteString("")
return buf.String()
}
// xml结构
func (this *PayApiController2) ParamsToXml2(data map[string]string) string {
fmt.Println(data)
buf := bytes.NewBufferString("")
for k, v := range data {
str := ""
flag, _ := regexp.MatchString("^\\d+\\.?\\d*$", v)
if flag {
str = "%s"
}
buf.WriteString(fmt.Sprintf("<%s>"+str+"%s>", k, v, k))
}
buf.WriteString("")
return buf.String()
}
func (this *PayApiController) SetUrl(payUrl string) {
this.payUrl = payUrl
}
func (c *PayApiController) GetHeTong() {
order_id, _ := c.GetInt64("order_id", 0)
if order_id <= 0 {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
return
}
admin := c.GetAdminUserInfo()
ht, err := service.GetHetong(admin.CurrentOrgId, order_id)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
c.ServeSuccessJSON(map[string]interface{}{
"ht": ht,
})
}
func (c *PayApiController) CreateHeTong() {
orderId, _ := c.GetInt64("order_id", 0)
if orderId <= 0 {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
return
}
admin := c.GetAdminUserInfo()
order, err := service.FindServeOrderByID(admin.CurrentOrgId, orderId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if order == nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeServeNotExist)
return
}
ht, err := service.GetHetong(admin.CurrentOrgId, orderId)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
return
}
if ht != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeHetongHad)
return
}
var hetong models.ServeOrderContract
err = json.Unmarshal(c.Ctx.Input.RequestBody, &hetong)
if err != nil {
fmt.Println(err)
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
return
}
hetong.OrderId = orderId
hetong.OrderNumber = order.OrderNumber
hetong.CreatedTime = time.Now().Unix()
hetong.UpdatedTime = time.Now().Unix()
hetong.Status = 1
hetong.OrgId = admin.CurrentOrgId
err = service.CreateHetong(&hetong)
if err != nil {
c.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeCreateHetongFail)
return
}
c.ServeSuccessJSON(map[string]interface{}{
"ht": hetong,
})
}