123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- 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("<xml>")
- for k, v := range data {
- str := "<![CDATA[%s]]>"
- flag, _ := regexp.MatchString("^\\d+\\.?\\d*$", v)
- if flag {
- str = "%s"
- }
- buf.WriteString(fmt.Sprintf("<%s>"+str+"</%s>", k, v, k))
- }
- buf.WriteString("</xml>")
- return buf.String()
- }
-
- // xml结构
- func (this *PayApiController2) ParamsToXml2(data map[string]string) string {
- fmt.Println(data)
- buf := bytes.NewBufferString("<xml>")
- for k, v := range data {
- str := "<![CDATA[%s]]>"
- flag, _ := regexp.MatchString("^\\d+\\.?\\d*$", v)
- if flag {
- str = "%s"
- }
- buf.WriteString(fmt.Sprintf("<%s>"+str+"</%s>", k, v, k))
- }
- buf.WriteString("</xml>")
- 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,
- })
- }
|