323 lines
8.8 KiB
Go
323 lines
8.8 KiB
Go
|
package payway
|
|||
|
|
|||
|
import (
|
|||
|
"bitbucket.org/skeris/treasurer/dal"
|
|||
|
"bytes"
|
|||
|
"context"
|
|||
|
"crypto/md5"
|
|||
|
"encoding/json"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"github.com/rs/xid"
|
|||
|
"io/ioutil"
|
|||
|
"log"
|
|||
|
"net/http"
|
|||
|
"net/url"
|
|||
|
"strconv"
|
|||
|
)
|
|||
|
|
|||
|
//#region ========= Payment =========
|
|||
|
|
|||
|
type ReqCreatePaymentUrlBt struct {
|
|||
|
Amount string `json:"amount"` // Required
|
|||
|
Currency string `json:"currency"` // Required
|
|||
|
OrderId string `json:"orderId"` // Required
|
|||
|
PaymentSystem string `json:"paymentSystem,omitempty"`
|
|||
|
UrlResult string `json:"urlResult,omitempty"`
|
|||
|
UrlSuccess string `json:"urlSuccess,omitempty"`
|
|||
|
UrlFail string `json:"urlFail,omitempty"`
|
|||
|
Locale string `json:"locale,omitempty"`
|
|||
|
PayerPhone string `json:"payerPhone,omitempty"`
|
|||
|
PayerName string `json:"payerName,omitempty"`
|
|||
|
PayerEmail string `json:"payerEmail,omitempty"`
|
|||
|
PayerFirstName string `json:"payer_firstname,omitempty"`
|
|||
|
PayerLastName string `json:"payer_lastname,omitempty"`
|
|||
|
PayerPostCode string `json:"payer_postcode,omitempty"`
|
|||
|
PayerAddress string `json:"payer_address,omitempty"`
|
|||
|
Ip string `json:"ip,omitempty"`
|
|||
|
UserComment string `json:"user_comment"` // Returned in Callback
|
|||
|
Sign string `json:"sign"` // Required
|
|||
|
}
|
|||
|
|
|||
|
type RespCreatePaymentUrlBt struct {
|
|||
|
Status interface{} `json:"status"`
|
|||
|
Id int64 `json:"id"`
|
|||
|
Url string `json:"url"`
|
|||
|
UrlPayment string `json:"urlPayment"`
|
|||
|
}
|
|||
|
|
|||
|
// CreatePaymentUrl - создает ссылку для перевода средств на кошелек (пополнение счета клиента)
|
|||
|
func (bt *BetaTransfer) CreatePaymentUrl(amount, orderID, paymentType, currency, lang, email, phone, requesterID,
|
|||
|
userIP string) (string, error) {
|
|||
|
action := UrlBt + "/payment?token=" + bt.Secret1
|
|||
|
|
|||
|
data := ReqCreatePaymentUrlBt{
|
|||
|
Amount: amount,
|
|||
|
Currency: currency,
|
|||
|
OrderId: orderID,
|
|||
|
PaymentSystem: paymentType,
|
|||
|
UrlResult: "",
|
|||
|
UrlSuccess: "",
|
|||
|
UrlFail: "",
|
|||
|
Locale: lang,
|
|||
|
PayerPhone: phone,
|
|||
|
PayerName: "",
|
|||
|
PayerEmail: email,
|
|||
|
PayerFirstName: "",
|
|||
|
PayerLastName: "",
|
|||
|
PayerPostCode: "",
|
|||
|
PayerAddress: "",
|
|||
|
Ip: "",
|
|||
|
UserComment: requesterID,
|
|||
|
Sign: "",
|
|||
|
}
|
|||
|
|
|||
|
body, err := bt.prepareData(data)
|
|||
|
|
|||
|
fmt.Println("Request:", string(body))
|
|||
|
if err != nil {
|
|||
|
fmt.Println("MarshalErr:", err)
|
|||
|
}
|
|||
|
|
|||
|
params := url.Values{}
|
|||
|
params.Add("amount", data.Amount)
|
|||
|
params.Add("currency", data.Currency)
|
|||
|
params.Add("orderId", xid.New().String())
|
|||
|
params.Add("paymentSystem", data.PaymentSystem)
|
|||
|
params.Add("locale", lang)
|
|||
|
params.Add("user_comment", orderID)
|
|||
|
json.Unmarshal(body, &data)
|
|||
|
params.Add("sign", data.Sign)
|
|||
|
|
|||
|
resp, err := http.PostForm(action, params)
|
|||
|
|
|||
|
fmt.Println("Status:", resp.Status)
|
|||
|
|
|||
|
var result RespCreatePaymentUrlBt
|
|||
|
bodyr, err := ioutil.ReadAll(resp.Body)
|
|||
|
if err != nil {
|
|||
|
log.Println(" ioutil: ", err)
|
|||
|
}
|
|||
|
if resp.StatusCode != 200 {
|
|||
|
|
|||
|
return "", errors.New("bad response: " + string(bodyr))
|
|||
|
}
|
|||
|
|
|||
|
err = json.Unmarshal(bodyr,&result)
|
|||
|
|
|||
|
if err != nil {
|
|||
|
log.Println(" json: ", err)
|
|||
|
}
|
|||
|
|
|||
|
fmt.Println(result)
|
|||
|
|
|||
|
return result.Url, nil
|
|||
|
}
|
|||
|
|
|||
|
// PaymentListener - Обрабатывает результат перевода
|
|||
|
func (bt *BetaTransfer) PaymentListener(ctx context.Context,ip string, request interface{}, mc *dal.MongoConnection) error {
|
|||
|
data := request.(*ReqPaymentListenerBt)
|
|||
|
if data.Sign != fmt.Sprintf("%x",
|
|||
|
md5.Sum([]byte(fmt.Sprint(data.Amount)+data.OrderId+bt.Secret2))) {
|
|||
|
return errors.New(fmt.Sprintf("wrong sign: %v, %s, %s", data.Sign, data.OrderId, bt.Secret2))
|
|||
|
}
|
|||
|
|
|||
|
// Проверка существования платежа в БД
|
|||
|
payment, err := mc.GetPayment(ctx, data.UserComment)
|
|||
|
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
|
|||
|
if payment == nil {
|
|||
|
return errors.New("payment not found")
|
|||
|
}
|
|||
|
|
|||
|
// Проверка статуса платежа (должен быть open)
|
|||
|
//if payment.Status != "open" || {
|
|||
|
// return errors.New(fmt.Sprintf("payment have status: %v", payment.Status))
|
|||
|
//}
|
|||
|
|
|||
|
// Проверка суммы платежа
|
|||
|
//if data.Amount != payment.Amount {
|
|||
|
// return errors.New(fmt.Sprintf("wrong amount: %v", data.Amount))
|
|||
|
//}
|
|||
|
//
|
|||
|
//// Проверка RequesterID
|
|||
|
//if data.RequesterID != payment.RequesterID {
|
|||
|
// return errors.New(fmt.Sprintf("wrong us_requesterID: %v", data.RequesterID))
|
|||
|
//}
|
|||
|
|
|||
|
// Обновление статуса платежа в БД
|
|||
|
if payment.Status != "accepted" {
|
|||
|
err = mc.UpdatePaymentStatus(ctx, data.UserComment, "accepted")
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (bt *BetaTransfer) GetPaymentList() ([]dal.PayWayPayment, error) {
|
|||
|
//TODO: implement me
|
|||
|
return bt.GetPaymentTypeList(), nil
|
|||
|
}
|
|||
|
|
|||
|
//#endregion
|
|||
|
|
|||
|
//#region ========= Payout =========
|
|||
|
|
|||
|
type ReqCreatePayoutBt struct {
|
|||
|
Amount string `json:"amount,omitempty"` // Required
|
|||
|
Currency string `json:"currency"` // Required
|
|||
|
OrderId string `json:"orderId"` // Required
|
|||
|
PaymentSystem string `json:"paymentSystem"` // Required
|
|||
|
UrlResult string `json:"urlResult,omitempty"`
|
|||
|
Address string `json:"address"` // Required. Purse
|
|||
|
Sign string `json:"sign"` // Required
|
|||
|
}
|
|||
|
|
|||
|
type RespCreatePayoutBt struct {
|
|||
|
Status string `json:"status"`
|
|||
|
Id int `json:"id"`
|
|||
|
PaymentSystem string `json:"paymentSystem"`
|
|||
|
OrderId string `json:"orderId"`
|
|||
|
OrderAmount string `json:"orderAmount"`
|
|||
|
OrderCurrency string `json:"orderCurrency"`
|
|||
|
PaymentAmount string `json:"paymentAmount"`
|
|||
|
PaymentCurrency string `json:"paymentCurrency"`
|
|||
|
Commission string `json:"commission"`
|
|||
|
CommissionCurrency string `json:"commissionCurrency"`
|
|||
|
}
|
|||
|
|
|||
|
// CreatePayout - выполняет запрос для вывода средств из кошелька (вывод средств со счета клиента).
|
|||
|
// В ответ получает RespCreatePayoutBt
|
|||
|
// purse - кошелек для вывода
|
|||
|
// amount - сумма для вывода
|
|||
|
// desc - описание/комментарий (OrderId)
|
|||
|
// exchange = 1 - отключить автообмен
|
|||
|
// currency - валюта для вывода
|
|||
|
func (bt *BetaTransfer) CreatePayout(amount, orderID, payoutType, currency, address string) (string, error) {
|
|||
|
action := UrlBt + "//withdrawal-payment?token=" + bt.Secret1
|
|||
|
payout := bt.GetPayoutType(payoutType)
|
|||
|
if currency == "" {
|
|||
|
currency = payout.Currency
|
|||
|
}
|
|||
|
|
|||
|
data := ReqCreatePayoutBt{
|
|||
|
Amount: amount,
|
|||
|
Currency: currency,
|
|||
|
OrderId: orderID,
|
|||
|
PaymentSystem: payoutType,
|
|||
|
UrlResult: "",
|
|||
|
Address: address,
|
|||
|
Sign: "",
|
|||
|
}
|
|||
|
|
|||
|
body, err := bt.prepareData(data)
|
|||
|
|
|||
|
if err != nil {
|
|||
|
fmt.Println("MarshalErr:", err)
|
|||
|
}
|
|||
|
|
|||
|
resp, err := http.Post(action, "application/json", bytes.NewReader(body))
|
|||
|
|
|||
|
defer func() {
|
|||
|
resp.Body.Close()
|
|||
|
}()
|
|||
|
|
|||
|
fmt.Println("Status:", resp.Status)
|
|||
|
|
|||
|
var result RespCreatePayoutBt
|
|||
|
|
|||
|
err = json.NewDecoder(resp.Body).Decode(&result)
|
|||
|
|
|||
|
if resp.StatusCode != 200 {
|
|||
|
body, err := ioutil.ReadAll(resp.Body)
|
|||
|
|
|||
|
if err != nil {
|
|||
|
log.Println(" ioutil: ", err)
|
|||
|
}
|
|||
|
return "", errors.New("bad response: " + string(body))
|
|||
|
}
|
|||
|
|
|||
|
fmt.Println(result)
|
|||
|
|
|||
|
return strconv.Itoa(result.Id), nil
|
|||
|
}
|
|||
|
|
|||
|
// PayoutListener - обрабатывает результат вывода
|
|||
|
func (bt *BetaTransfer) PayoutListener(ctx context.Context, ip string, request interface{}, mc *dal.MongoConnection) error {
|
|||
|
fmt.Println("bt.PayoutListener:", request)
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (bt *BetaTransfer) GetPayoutList() ([]dal.PayoutType, error) {
|
|||
|
//TODO: implement me
|
|||
|
return bt.GetPayoutTypeList(), nil
|
|||
|
}
|
|||
|
|
|||
|
//#endregion
|
|||
|
|
|||
|
//#region ========= Wallet =========
|
|||
|
|
|||
|
type RespGetWalletBalanceBt struct {
|
|||
|
Account struct {
|
|||
|
LockWithdrawal bool `json:"lockWithdrawal"`
|
|||
|
LockAccount bool `json:"lockAccount"`
|
|||
|
AuthAt int `json:"authAt"`
|
|||
|
} `json:"account"`
|
|||
|
Balance map[string]string `json:"balance"`
|
|||
|
BalanceOnHold map[string]string `json:"balance_on_hold"`
|
|||
|
}
|
|||
|
|
|||
|
// GetWalletBalance - выполняет запрос чтобы узнать баланс кошелька
|
|||
|
func (bt *BetaTransfer) GetWalletBalance() (map[string]float64, error) {
|
|||
|
action := UrlBt + "/account-info"
|
|||
|
|
|||
|
params := url.Values{
|
|||
|
"token": {bt.Secret1},
|
|||
|
"sign": {bt.createSign([]string{bt.Secret1})},
|
|||
|
}
|
|||
|
|
|||
|
action += fmt.Sprintf("?%v", params.Encode())
|
|||
|
|
|||
|
client := &http.Client{}
|
|||
|
resp, err := client.Get(action)
|
|||
|
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
if resp.StatusCode != http.StatusOK {
|
|||
|
return nil, errors.New(fmt.Sprintf("got bad status: %v", resp.Status))
|
|||
|
}
|
|||
|
|
|||
|
var response RespGetWalletBalanceBt
|
|||
|
|
|||
|
err = json.NewDecoder(resp.Body).Decode(&response)
|
|||
|
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
var result map[string]float64
|
|||
|
|
|||
|
for key, val := range response.Balance {
|
|||
|
if val == "" {
|
|||
|
val = "0.0"
|
|||
|
}
|
|||
|
|
|||
|
toFloat, err := strconv.ParseFloat(val, 64)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
result[key] = toFloat
|
|||
|
}
|
|||
|
|
|||
|
return result, nil
|
|||
|
}
|
|||
|
|
|||
|
//#endregion
|