330 lines
7.5 KiB
Go
330 lines
7.5 KiB
Go
|
package fk
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto/hmac"
|
||
|
"crypto/sha256"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"net/http"
|
||
|
"reflect"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
const UrlFk = "https://api.freekassa.ru/v1"
|
||
|
|
||
|
type ReqCreateInvoice struct {
|
||
|
ShopId int64 `json:"shopId"`
|
||
|
Nonce int64 `json:"none"`
|
||
|
Signature string `json:"signature"`
|
||
|
PaymentId string `json:"paymentId"`
|
||
|
I int64 `json:"i"`
|
||
|
Email string `json:"email"`
|
||
|
IP string `json:"ip"`
|
||
|
Amount float64 `json:"amount"`
|
||
|
Currency string `json:"currency"`
|
||
|
Tel string `json:"tel"`
|
||
|
SuccessUrl string `json:"successUrl,omitempty"`
|
||
|
FailureUrl string `json:"failureUrl,omitempty"`
|
||
|
NotificationUrl string `json:"motificationUrl,omitempty"`
|
||
|
}
|
||
|
|
||
|
type RespCreateInvoice struct {
|
||
|
Type string `json:"type"`
|
||
|
OrderId int `json:"order_id"`
|
||
|
OrderHash string `json:"order_hash"`
|
||
|
Location string `json:"location"`
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) CreatePaymentUrl(paymentType int64, amount float64, orderId, email, ip, currency, phone string) (string, error) {
|
||
|
body, err := pw.create(&ReqCreateInvoice{
|
||
|
ShopId: pw.ShopId,
|
||
|
Nonce: time.Now().Unix(),
|
||
|
PaymentId: orderId,
|
||
|
I: paymentType,
|
||
|
Email: email,
|
||
|
IP: ip,
|
||
|
Amount: amount,
|
||
|
Currency: currency,
|
||
|
Tel: phone,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
resp, err := http.Post(UrlFk+"/orders/create", "application/json", bytes.NewReader(body))
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
if resp.StatusCode != 200 {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
var result RespCreateInvoice
|
||
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
if result.Type != "success" {
|
||
|
return "", fmt.Errorf("create link bad response: %v", result)
|
||
|
}
|
||
|
|
||
|
return result.Location, nil
|
||
|
}
|
||
|
|
||
|
type ReqOrdersHistory struct {
|
||
|
ShopId int64 `json:"id"`
|
||
|
Nonce int64 `json:"nonce"`
|
||
|
Signature string `json:"signature"`
|
||
|
DateFrom string `json:"dateFrom"`
|
||
|
DateTo string `json:"dateTo"`
|
||
|
}
|
||
|
|
||
|
type RespOrdersHistory struct {
|
||
|
Type string `json:"type"`
|
||
|
Pages int64 `json:"pages"`
|
||
|
Orders []Order `json:"orders"`
|
||
|
}
|
||
|
|
||
|
type Order struct {
|
||
|
MerchantOrderId string `json:"merchant_order_id"`
|
||
|
FkOrderId int64 `json:"fk_order_id"`
|
||
|
Amount float64 `json:"amount"`
|
||
|
Currency string `json:"currency"`
|
||
|
Email string `json:"email"`
|
||
|
Account string `json:"account"`
|
||
|
Date string `json:"date"`
|
||
|
Status int `json:"status"`
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) GetOrdersHistory() ([]Order, error) {
|
||
|
var resp RespOrdersHistory
|
||
|
|
||
|
if err := pw.apiRequest("https://api.freekassa.ru/v1/orders", &pw.getOrders, &ReqOrdersHistory{
|
||
|
ShopId: pw.ShopId,
|
||
|
Nonce: time.Now().Unix(),
|
||
|
}, &resp); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return resp.Orders, nil
|
||
|
}
|
||
|
|
||
|
type ReqGetWallet struct {
|
||
|
ShopId int64 `json:"shopId"`
|
||
|
Nonce int64 `json:"nonce"`
|
||
|
Signature string `json:"signature"`
|
||
|
}
|
||
|
|
||
|
type WalletResp struct {
|
||
|
Type string `json:"type"`
|
||
|
Balance []Wallet `json:"balance"`
|
||
|
}
|
||
|
|
||
|
type Wallet struct {
|
||
|
Currency string `json:"currency" bson:"cur"`
|
||
|
Value string `json:"value" bson:"val"`
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) GetWallet() ([]Wallet, error) {
|
||
|
var resp WalletResp
|
||
|
if err := pw.apiRequest("https://api.freekassa.ru/v1/balance", &pw.wallet, &ReqGetWallet{
|
||
|
ShopId: pw.ShopId,
|
||
|
Nonce: time.Now().Unix(),
|
||
|
}, &resp); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
fmt.Println("wallet", resp)
|
||
|
|
||
|
return resp.Balance, nil
|
||
|
}
|
||
|
|
||
|
type CurreciesResp struct {
|
||
|
Type string `json:"type"`
|
||
|
Currencies []Currency `json:"currencies"`
|
||
|
}
|
||
|
|
||
|
type Currency struct {
|
||
|
Id int `json:"id" bson:"id"`
|
||
|
Name string `json:"name" bson:"name"`
|
||
|
Currency string `json:"currency" bson:"cur"`
|
||
|
IsEnabled uint8 `json:"is_enabled" bson:"is_enabled"`
|
||
|
IsFavourite uint8 `json:"is_favourite" bson:"is_fav"`
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) GetCurrencies() ([]Currency, error) {
|
||
|
var resp CurreciesResp
|
||
|
|
||
|
if err := pw.apiRequest("https://api.freekassa.ru/v1/currencies", &pw.wallet, &ReqGetWallet{
|
||
|
ShopId: pw.ShopId,
|
||
|
Nonce: time.Now().Unix(),
|
||
|
}, &resp); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
fmt.Println("currencies", resp)
|
||
|
|
||
|
return resp.Currencies, nil
|
||
|
}
|
||
|
|
||
|
type ShopResp struct {
|
||
|
Type string `json:"type"`
|
||
|
Shops []Shop `json:"shops"`
|
||
|
}
|
||
|
|
||
|
type Shop struct {
|
||
|
Id int `json:"id" bson:"id"`
|
||
|
Name string `json:"name" bson:"name"`
|
||
|
Url string `json:"url" bson:"url"`
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) GetShops() ([]Shop, error) {
|
||
|
var resp ShopResp
|
||
|
|
||
|
if err := pw.apiRequest("https://api.freekassa.ru/v1/shops", &pw.wallet, &ReqGetWallet{
|
||
|
ShopId: pw.ShopId,
|
||
|
Nonce: time.Now().Unix(),
|
||
|
}, &resp); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
fmt.Println("shops", resp)
|
||
|
|
||
|
return resp.Shops, nil
|
||
|
}
|
||
|
|
||
|
type WithdrawalCurrenciesResp struct {
|
||
|
Type string `json:"type"`
|
||
|
Currencies []WithdrawalCurrencie `json:"currencies"`
|
||
|
}
|
||
|
|
||
|
type WithdrawalCurrencie struct {
|
||
|
Id int `json:"id" bson:"id"`
|
||
|
Name string `json:"name" bson:"name"`
|
||
|
Min float64 `json:"min" bson:"min"`
|
||
|
Max float64 `json:"max" bson:"max"`
|
||
|
Currency string `json:"currency" bson:"cur"`
|
||
|
CanExcahnge uint8 `json:"can_exchange" bson:"can_exch"`
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) GetWithdrawalCurrencies() ([]WithdrawalCurrencie, error) {
|
||
|
var resp WithdrawalCurrenciesResp
|
||
|
|
||
|
if err := pw.apiRequest("https://api.freekassa.ru/v1/withdrawals/currencies", &pw.wallet, &ReqGetWallet{
|
||
|
ShopId: pw.ShopId,
|
||
|
Nonce: time.Now().Unix(),
|
||
|
}, &resp); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
fmt.Println("withdrawals cur", resp)
|
||
|
|
||
|
return resp.Currencies, nil
|
||
|
}
|
||
|
|
||
|
type Access struct {
|
||
|
Type string `json:"type"`
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) Accesable(id int) (bool, error) {
|
||
|
var resp Access
|
||
|
if err := pw.apiRequest(fmt.Sprintf("https://api.freekassa.ru/currencies/%d/status", id), &pw.wallet, &ReqGetWallet{
|
||
|
ShopId: pw.ShopId,
|
||
|
Nonce: time.Now().Unix(),
|
||
|
}, &resp); err != nil {
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
if resp.Type != "success" {
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) apiRequest(url string, p *preparer, r, dest any) error {
|
||
|
body, err := (*p)(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
resp, err := http.Post(url, "application/json", bytes.NewBuffer(body))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
if resp.StatusCode != http.StatusOK {
|
||
|
b, err := ioutil.ReadAll(resp.Body)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return fmt.Errorf("status code: %d\nbad response: %s", resp.StatusCode, string(b))
|
||
|
}
|
||
|
|
||
|
if err := json.NewDecoder(resp.Body).Decode(dest); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) prepareData(shape any) func(data any) ([]byte, error) {
|
||
|
var (
|
||
|
sind []int
|
||
|
indexes [][]int
|
||
|
)
|
||
|
|
||
|
func() {
|
||
|
var (
|
||
|
fieldNames []string
|
||
|
ind = map[string][]int{}
|
||
|
)
|
||
|
|
||
|
for _, f := range reflect.VisibleFields(reflect.Indirect(reflect.ValueOf(shape)).Type()) {
|
||
|
name := strings.Split(f.Tag.Get("json"), ",")[0]
|
||
|
if name != "signature" {
|
||
|
fieldNames = append(fieldNames, name)
|
||
|
ind[name] = f.Index
|
||
|
} else {
|
||
|
sind = f.Index
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sort.Strings(fieldNames)
|
||
|
|
||
|
for _, i := range fieldNames {
|
||
|
indexes = append(indexes, ind[i])
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
return func(data any) ([]byte, error) {
|
||
|
val := reflect.Indirect(reflect.ValueOf(data))
|
||
|
|
||
|
var forsign []string
|
||
|
|
||
|
for _, fn := range indexes {
|
||
|
forsign = append(forsign, fmt.Sprint(val.FieldByIndex(fn)))
|
||
|
}
|
||
|
|
||
|
val.FieldByIndex(sind).Set(reflect.ValueOf(pw.createSign([]byte(strings.Join(forsign, "|")))))
|
||
|
|
||
|
return json.Marshal(data)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (pw *FreeKassa) createSign(data []byte) string {
|
||
|
sign := hmac.New(sha256.New, pw.byteKey)
|
||
|
sign.Write(data)
|
||
|
return fmt.Sprintf("%x", sign.Sum(nil))
|
||
|
}
|