Procházet zdrojové kódy

rpnIn sort of tested.

master
patrick před 5 roky
rodič
revize
d6ab57aae0
7 změnil soubory, kde provedl 273 přidání a 201 odebrání
  1. +1
    -2
      config.go
  2. +1
    -1
      db.go
  3. +2
    -3
      leanwork_request.go
  4. +17
    -185
      rpn.go
  5. +62
    -10
      rpnIn.go
  6. +52
    -0
      rpnIn_test.go
  7. +138
    -0
      rpnOut.go

+ 1
- 2
config.go Zobrazit soubor

@@ -2,7 +2,6 @@ package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
)
@@ -59,6 +58,6 @@ func readConfigFile(file string) error {
log.Fatal("cannot print back to json")
return err
}
fmt.Println(string(j))
log.Println(string(j))
return err
}

+ 1
- 1
db.go Zobrazit soubor

@@ -21,7 +21,7 @@ func (m *TransactionDB) conn(c AppConfig) error {
dbUser := c.DB.User
dbPass := c.DB.Pass
dbName := c.DB.Schema
h, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@/"+dbName)
h, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@/"+dbName+"?parseTime=true")
if err != nil {
m.h = nil
panic(err.Error())

+ 2
- 3
leanwork_request.go Zobrazit soubor

@@ -2,8 +2,7 @@ package main

import (
"errors"

"github.com/go-sql-driver/mysql"
"time"
)

type LeanworkRequest struct {
@@ -17,7 +16,7 @@ type LeanworkRequest struct {
CustomerId string
Sign string
Valid bool
Ts mysql.NullTime
Ts time.Time
Ip4 uint32
Ip4Location string
}

+ 17
- 185
rpn.go Zobrazit soubor

@@ -1,169 +1,30 @@
package main

import (
"database/sql"
"errors"
"fmt"
"log"
"math"
"net/http"
"net/url"
"strconv"
"time"

"github.com/go-sql-driver/mysql"
)

type RpnOut struct {
Version string
Sign_type string
Mid string
Notify_url string
Order_amount string
Order_time string //YYYYMMDDHHMMSS
Order_id string
User_id string
User_name string
User_cardno string
Signature string
//template
Url string //where to post entire data structure
//database specific
Id int64
Leanwork int64
Ip4 uint32
Ip4location sql.NullString
Ts mysql.NullTime
}

// //build request from leanwork request forms
// func (m *RpnOut) buildReqByForm(form url.Values) RpnOut {
// r := RpnOut{}
// r.version = "1.1"
// r.sign_type = "MD5"
// r.mid = "EU85201311P2P"
// r.notify_url = "http://rpn.supertraderfx.ayvwd8em49pvoa3g.com/rpn_notify"
// r.order_id = form["orderNo"][0]
// r.order_amount = form["orderAmount"][0] //cents
// r.order_time = m.now()
// r.user_id = form["customerId"][0]
// r.user_name = "SuperForex"
// r.user_cardno = "6212262002002377849"
// r.signature = md5RpnFormP2P(r)
// *m = r
// return r
// }

func (m *RpnOut) buildReqByLeanworkRequestP2P(row LeanworkRequest, user_name string, user_cardno string) RpnOut {

m.Version = "1.1"
m.Sign_type = "MD5"
m.Mid = Config.Rpn.MIDP2P
m.Notify_url = Config.Rpn.UrlCallBack
m.Order_id = row.OrderNo
m.Order_amount = m.translateAmountFromLeanwork(row.OrderAmount)
m.Order_time = m.now()
m.User_id = row.CustomerId
m.User_name = user_name
m.User_cardno = user_cardno
m.Signature = md5RpnFormP2P(*m)
m.Leanwork = row.Id

return *m
}

func (m *RpnOut) buildReqByLeanworkRequestFAT(row LeanworkRequest, user_name string, user_cardno string) RpnOut {
m.Version = "1.1"
m.Sign_type = "MD5"
m.Mid = Config.Rpn.MIDFAT
m.Notify_url = Config.Rpn.UrlCallBack
m.Order_id = row.OrderNo
m.Order_amount = m.translateAmountFromLeanwork(row.OrderAmount)
m.Order_time = m.now()
m.User_id = row.CustomerId
m.User_name = user_name
m.User_cardno = user_cardno
m.Signature = md5RpnFormFAT(*m)
m.Leanwork = row.Id
return *m
}

//from 0.1 to 10 cents
func (m *RpnOut) translateAmountFromLeanwork(from string) string {
f, _ := strconv.ParseFloat(from, 32)
f = f * 100 //convert to cents
t := int(math.Ceil(f))
s := strconv.Itoa(t)
return s
}

func (m *RpnOut) now() string {
t := time.Now()
return t.Format("20060102150405")
}

//send request to RPN to initiate transaction
func (m *RpnOut) SendReq(form url.Values) (*http.Response, error) {
return nil, nil
// r := m.buildReqByForm(form)
// hc := http.Client{Timeout: 15 * time.Second}

// myForm := url.Values{}
// myForm.Set("version", r.version)
// myForm.Set("sign_type", r.sign_type)
// myForm.Set("mid", r.mid)
// myForm.Set("notify_url", r.notify_url)
// myForm.Set("order_id", r.order_id)
// myForm.Set("order_amount", r.order_amount)
// myForm.Set("order_time", r.order_time)
// myForm.Set("user_id", r.user_id)
// myForm.Set("user_name", r.user_name)
// myForm.Set("user_cardno", r.user_cardno)
// myForm.Set("signature", r.signature)

// //req, err := http.NewRequest("POST", "https://lawipac.com/dumprequest.php", strings.NewReader(myForm.Encode()))
// req, err := http.NewRequest("POST", Config.Rpn.UrlTest, strings.NewReader(m.encode()))
// if err != nil {
// panic("wrong")
// }
// req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
// req.Header.Add("content-Length", strconv.Itoa(len(form.Encode())))
// return hc.Do(req)
//Config.Rpn.UrlTest
// return http.PostForm(Config.Rpn.UrlTest, myForm)
//return http.PostForm("https://lawipac.com/dumprequest.php", myForm)

}

//encode without disturbing it's original order
func (m *RpnOut) encode() string {
s := "version=" + m.Version
s += "&sign_type=" + m.Sign_type
s += "&mid=" + m.Mid
s += "&notify_url=" + url.QueryEscape(m.Notify_url)
s += "&order_id=" + m.Order_id
s += "&order_amount=" + m.Order_amount
s += "&order_time=" + m.Order_time
s += "&user_id=" + m.User_id
s += "&user_name=" + url.QueryEscape(m.User_name)
s += "&user_cardno=" + m.User_cardno
s += "&signature=" + m.Signature
return s
}

func retrieveFormValue(form url.Values, key string) (r string, err error) {
func rpnNotify(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
errPage(w, http.StatusMethodNotAllowed, "invalid request")
return
}
ri, err := GetRpnInFromHTTPRequest(r) //ParseForm called
if err != nil {
errPage(w, http.StatusBadRequest, "invalid parameters")
return
}

if _, ok := form[key]; ok {
r = form[key][0]
err = nil
} else {
r = ""
err = errors.New("Key [" + key + "] not found in HTTP request")
ro, _ := getRpnOutByOrderId(ri.Order_id)
ri.Leanwork = ro.Leanwork
ri1, err := ri.add2db() //TODO:check error add
if err != nil {
log.Printf("failed to add rpnIn %+v , error is %s", ri, err.Error())
}
return r, err
}
func rpnNotify(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "ok notify")
fmt.Fprintf(w, "[SUCCESS]")
return
}

//receive RPN user name and card number
@@ -205,32 +66,3 @@ func rpnNameAndCard(w http.ResponseWriter, r *http.Request) {
//build rpn redirect page and send it
ro.sendRedirect(w, row)
}

func (m *RpnOut) sendRedirect(w http.ResponseWriter, row LeanworkRequest) {
//execute redirect
m.Url = Config.Rpn.Url
tmpl.ExecuteTemplate(w, "rpnCallOutRedirect", *m)
}

func getRpnOutByOrderId(order_id string) (ret RpnOut, err error) {
if err = db.conn(Config); err != nil {
return
}
defer db.close()

q := "SELECT * FROM rpnOut WHERE order_id = ? ORDER BY id DESC LIMIT 1"
err = db.h.QueryRow(q, order_id).Scan(
&ret.Id, &ret.Leanwork, &ret.Version,
&ret.Sign_type, &ret.Mid, &ret.Notify_url,
&ret.Order_amount, &ret.Order_time, &ret.Order_id,
&ret.User_id, &ret.User_name, &ret.User_cardno, &ret.Signature,
&ret.Ip4, &ret.Ip4location, &ret.Ts)
if err != nil {
if err == sql.ErrNoRows {
log.Println("trying to retrieve rpnOut(order_id=" + order_id + ") but not found")
} else {
log.Println("Error retrieving rpnOut(order_id=" + order_id + ") encountered : " + err.Error())
}
}
return
}

+ 62
- 10
rpnIn.go Zobrazit soubor

@@ -2,10 +2,11 @@ package main

import (
"database/sql"
"errors"
"log"
"net/http"
"strconv"

"github.com/go-sql-driver/mysql"
"time"
)

type RpnIn struct {
@@ -19,7 +20,8 @@ type RpnIn struct {
Pay_amount string
Pay_result string
Signature string
Ts mysql.NullTime
Ts time.Time
Ip4 uint32
}

//get given RpnIn record based on ID
@@ -34,7 +36,7 @@ func getRpnInById(id int64) (ret RpnIn, err error) {
&ret.Id, &ret.Leanwork, &ret.Order_id,
&ret.Order_time, &ret.Order_amount, &ret.Deal_id,
&ret.Deal_time, &ret.Pay_amount, &ret.Pay_result,
&ret.Signature, &ret.Ts)
&ret.Signature, &ret.Ts, &ret.Ip4)
if err != nil {
if err == sql.ErrNoRows {
log.Println("trying to retrieve rpnIn(" + strconv.FormatInt(id, 10) + ") but not found")
@@ -46,27 +48,27 @@ func getRpnInById(id int64) (ret RpnIn, err error) {
}

//add to database
func (m *RpnIn) add() (ret RpnIn, err error) {
func (m *RpnIn) add2db() (ret RpnIn, err error) {
if err = db.conn(Config); err != nil {
return
}
defer db.close()

q := `"INSERT INTO rpnIn(
q := `INSERT INTO rpnIn(
leanwork, order_id, order_time, order_amount, deal_id,
deal_time, pay_amount, pay_result, signature)
VALUES(?,?,?,?,?,?,?,?,?)
`
insForm, err := db.h.Prepare(q)
if err != nil {
log.Printf("Failed to prepare SQL statment for insert")
log.Printf("Failed to prepare SQL statment for insert " + err.Error())
return
}
res, err := insForm.Exec(
m.Leanwork, m.Order_id, m.Order_time, m.Order_amount, m.Deal_id,
m.Deal_time, m.Pay_amount, m.Pay_result, m.Signature)
if err != nil {
log.Printf("Error inserting rpnIn with orderNo =%s \n", m.Order_id)
log.Printf("Error inserting rpnIn with orderNo =%s, %s \n", m.Order_id, err.Error())
return
}
id, err := res.LastInsertId()
@@ -75,7 +77,12 @@ func (m *RpnIn) add() (ret RpnIn, err error) {
return
}

return getRpnInById(id)
ret, err = getRpnInById(id)
if err == nil {
*m = ret
}

return
}

func (m *RpnIn) signature() string {
@@ -86,6 +93,51 @@ func (m *RpnIn) signature() string {
s += "|deal_time=" + m.Deal_time
s += "|pay_amount=" + m.Pay_amount
s += "|pay_result=" + m.Pay_result
s += "|key=" + m.md5key()
return md5str(s)
}

func (m *RpnIn) md5key() string {
if m.Order_id == "" {
return ""
}

ro, err := getRpnOutByOrderId(m.Order_id)
if err != nil {
log.Println("Cannot get RpnOut by order_id=" + m.Order_id)
return ""
}
return ro.getMD5Key()
}

return s
func GetRpnInFromHTTPRequest(r *http.Request) (ret RpnIn, err error) {
r.ParseForm()
ret.Order_id = r.FormValue("order_id")
ret.Order_time = r.FormValue("order_time")
ret.Order_amount = r.FormValue("order_amount")
ret.Deal_id = r.FormValue("deal_id")
ret.Deal_time = r.FormValue("deal_time")
ret.Pay_amount = r.FormValue("pay_amount")
ret.Pay_result = r.FormValue("pay_result")
ret.Signature = r.FormValue("signature")
ret.Ip4 = getClientIPLong(r)
ret.Ts = time.Now()

if ret.Order_id == "" {
err = errors.New("Invalid OrderId for RpnIn")
return
}

ro, err := getRpnOutByOrderId(ret.Order_id)
if err != nil || ro.Order_id != ret.Order_id {
log.Println("Cannot get RpnOut by order_id=" + ret.Order_id)
return
}

if ret.Signature != ret.signature() {
log.Println("Invalid RpnIn Signature")
err = errors.New("Invalid signauture for RpnIn")
return
}
return
}

+ 52
- 0
rpnIn_test.go Zobrazit soubor

@@ -0,0 +1,52 @@
package main

import (
"io/ioutil"
"net/http"
"net/url"
"testing"
"time"
)

func TestRpnInCall(t *testing.T) {
form := url.Values{}
ri := RpnIn{}
ri.Order_id = "200310160057TW002184000000000001"
ri.Order_time = time.Now().Format("20060102150405")
ri.Order_amount = "120000"
ri.Deal_id = "deal_id_demo_01"
ri.Deal_time = time.Now().Format("20060102150405")
ri.Pay_amount = "120000"
ri.Pay_result = "3" //3 success, 1 processing
ri.Signature = ri.signature()

form.Set("order_id", ri.Order_id)
form.Set("order_time", ri.Order_time)
form.Set("order_amount", ri.Order_amount)
form.Set("deal_id", ri.Deal_id)
form.Set("deal_time", ri.Deal_time)
form.Set("pay_amount", ri.Pay_amount)
form.Set("pay_result", ri.Pay_result)
form.Set("signature", ri.Signature)

resp, err := http.PostForm(Config.Rpn.UrlCallBack, form)
if err != nil {
t.Error("response should have no error")
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
t.Error("response should be OK 200")
}

bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Error("response Body cannot be read")
}

bodyString := string(bodyBytes)
if bodyString != "[SUCCESS]" {
t.Error("we expect [SUCCESS] but we received:" + bodyString)
}

}

+ 138
- 0
rpnOut.go Zobrazit soubor

@@ -0,0 +1,138 @@
package main

import (
"database/sql"
"log"
"math"
"net/http"
"net/url"
"strconv"
"time"

"github.com/go-sql-driver/mysql"
)

type RpnOut struct {
Version string
Sign_type string
Mid string
Notify_url string
Order_amount string
Order_time string //YYYYMMDDHHMMSS
Order_id string
User_id string
User_name string
User_cardno string
Signature string
//template
Url string //where to post entire data structure
//database specific
Id int64
Leanwork int64
Ip4 uint32
Ip4location sql.NullString
Ts mysql.NullTime
}

func (m *RpnOut) buildReqByLeanworkRequestP2P(row LeanworkRequest, user_name string, user_cardno string) RpnOut {

m.Version = "1.1"
m.Sign_type = "MD5"
m.Mid = Config.Rpn.MIDP2P
m.Notify_url = Config.Rpn.UrlCallBack
m.Order_id = row.OrderNo
m.Order_amount = m.translateAmountFromLeanwork(row.OrderAmount)
m.Order_time = m.now()
m.User_id = row.CustomerId
m.User_name = user_name
m.User_cardno = user_cardno
m.Signature = md5RpnFormP2P(*m)
m.Leanwork = row.Id

return *m
}

func (m *RpnOut) buildReqByLeanworkRequestFAT(row LeanworkRequest, user_name string, user_cardno string) RpnOut {
m.Version = "1.1"
m.Sign_type = "MD5"
m.Mid = Config.Rpn.MIDFAT
m.Notify_url = Config.Rpn.UrlCallBack
m.Order_id = row.OrderNo
m.Order_amount = m.translateAmountFromLeanwork(row.OrderAmount)
m.Order_time = m.now()
m.User_id = row.CustomerId
m.User_name = user_name
m.User_cardno = user_cardno
m.Signature = md5RpnFormFAT(*m)
m.Leanwork = row.Id
return *m
}

//from 0.1 to 10 cents
func (m *RpnOut) translateAmountFromLeanwork(from string) string {
f, _ := strconv.ParseFloat(from, 32)
f = f * 100 //convert to cents
t := int(math.Ceil(f))
s := strconv.Itoa(t)
return s
}

func (m *RpnOut) now() string {
t := time.Now()
return t.Format("20060102150405")
}

//encode without disturbing it's original order
func (m *RpnOut) encode() string {
s := "version=" + m.Version
s += "&sign_type=" + m.Sign_type
s += "&mid=" + m.Mid
s += "&notify_url=" + url.QueryEscape(m.Notify_url)
s += "&order_id=" + m.Order_id
s += "&order_amount=" + m.Order_amount
s += "&order_time=" + m.Order_time
s += "&user_id=" + m.User_id
s += "&user_name=" + url.QueryEscape(m.User_name)
s += "&user_cardno=" + m.User_cardno
s += "&signature=" + m.Signature
return s
}

func (m *RpnOut) sendRedirect(w http.ResponseWriter, row LeanworkRequest) {
//execute redirect
m.Url = Config.Rpn.Url
tmpl.ExecuteTemplate(w, "rpnCallOutRedirect", *m)
}

func (m *RpnOut) getMD5Key() string {
if m.Mid == Config.Rpn.MIDP2P {
return Config.Rpn.MD5P2P
} else if m.Mid == Config.Rpn.MD5FAT {
return Config.Rpn.MD5FAT
} else {
return ""
}
}

func getRpnOutByOrderId(order_id string) (ret RpnOut, err error) {
if err = db.conn(Config); err != nil {
return
}
defer db.close()

q := "SELECT * FROM rpnOut WHERE order_id = ? ORDER BY id DESC LIMIT 1"
err = db.h.QueryRow(q, order_id).Scan(
&ret.Id, &ret.Leanwork, &ret.Version,
&ret.Sign_type, &ret.Mid, &ret.Notify_url,
&ret.Order_amount, &ret.Order_time, &ret.Order_id,
&ret.User_id, &ret.User_name, &ret.User_cardno, &ret.Signature,
&ret.Ip4, &ret.Ip4location, &ret.Ts)
if err != nil {
if err == sql.ErrNoRows {
log.Println("trying to retrieve rpnOut(order_id=" + order_id + ") but not found")
} else {
log.Println("Error retrieving rpnOut(order_id=" + order_id + ") encountered : " + err.Error())
}
}
return
}

Načítá se…
Zrušit
Uložit