package perfectmoney import ( "crypto/md5" "encoding/hex" "fmt" "io/ioutil" "net/http" "net/url" "regexp" "strconv" "strings" "time" ) type PerfectMoney struct { account string passwd string } func NewPerfectMoney(account, passwd string) *PerfectMoney { return &PerfectMoney{ account: account, passwd: passwd, } } func (pm *PerfectMoney) fetch(endpoint string, params url.Values) (string, error) { finalURL := fmt.Sprintf("https://perfectmoney.com/acct/%s.asp", endpoint) if params == nil { params = url.Values{} } params.Add("AccountID", pm.account) params.Add("PassPhrase", pm.passwd) resp, err := http.PostForm(finalURL, params) if err != nil { return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } return string(body), nil } func parseResponse(body string) (map[string]string, error) { result := make(map[string]string) errorRe := regexp.MustCompile("") valueRe := regexp.MustCompile("") if errorMatch := errorRe.FindStringSubmatch(body); errorMatch != nil { return nil, fmt.Errorf(errorMatch[1]) } matches := valueRe.FindAllStringSubmatch(body, -1) for _, match := range matches { result[match[1]] = match[2] } return result, nil } func (pm *PerfectMoney) Balance() (map[string]string, error) { body, err := pm.fetch("balance", nil) if err != nil { return nil, err } return parseResponse(body) } func (pm *PerfectMoney) History(start, end time.Time) ([]string, error) { params := url.Values{} params.Add("startday", strconv.Itoa(start.Day())) params.Add("startmonth", strconv.Itoa(int(start.Month()))) params.Add("startyear", strconv.Itoa(start.Year())) params.Add("endday", strconv.Itoa(end.Day())) params.Add("endmonth", strconv.Itoa(int(end.Month()))) params.Add("endyear", strconv.Itoa(end.Year())) body, err := pm.fetch("historycsv", params) if err != nil { return nil, err } lines := strings.Split(body, "\n") return lines[1:], nil // Skipping the CSV header } func (pm *PerfectMoney) Transfer(payer, payee string, amount float64, memo, paymentID string) (map[string]string, error) { params := url.Values{} params.Add("Payer_Account", payer) params.Add("Payee_Account", payee) params.Add("Amount", fmt.Sprintf("%.2f", amount)) params.Add("Memo", memo) params.Add("PAYMENT_ID", paymentID) body, err := pm.fetch("confirm", params) if err != nil { return nil, err } return parseResponse(body) } func (pm *PerfectMoney) EVCreate(payer string, amount float64) (map[string]string, error) { params := url.Values{} params.Add("Payer_Account", payer) params.Add("Amount", fmt.Sprintf("%.2f", amount)) body, err := pm.fetch("ev_create", params) if err != nil { return nil, err } return parseResponse(body) } func (pm *PerfectMoney) EVCsv() ([]string, error) { body, err := pm.fetch("evcsv", nil) if err != nil { return nil, err } lines := strings.Split(body, "\n") return lines[1:], nil // Skipping the CSV header } func (pm *PerfectMoney) Check(payee, payer string, amount float64, units, batchNumber, secret, timestamp, paymentID, v2Hash string) bool { data := fmt.Sprintf("%s:%s:%.2f:%s:%s:%s:%s:%s", paymentID, payee, amount, units, batchNumber, payer, secret, timestamp) hash := md5.Sum([]byte(data)) calculatedHash := strings.ToUpper(hex.EncodeToString(hash[:])) return calculatedHash == v2Hash }