-
Notifications
You must be signed in to change notification settings - Fork 14
/
notification.go
92 lines (79 loc) · 3.55 KB
/
notification.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package tinkoff
import (
"encoding/json"
"errors"
"fmt"
"io"
"strconv"
)
type Notification struct {
TerminalKey string `json:"TerminalKey"` // Идентификатор магазина
OrderID string `json:"OrderId"` // Номер заказа в системе Продавца
Success bool `json:"Success"` // Успешность операции
Status string `json:"Status"` // Статус платежа (см. описание статусов операций)
PaymentID uint64 `json:"PaymentId"` // Уникальный идентификатор платежа. В случае нотификаций банк присылает число, а не строку, как в случае с Init или Cancel
ErrorCode string `json:"ErrorCode"` // Код ошибки, если произошла ошибка
Amount uint64 `json:"Amount"` // Текущая сумма транзакции в копейках
RebillID string `json:"RebillId"` // Идентификатор рекуррентного платежа
CardID uint64 `json:"CardId"` // Идентификатор привязанной карты
PAN string `json:"Pan"` // Маскированный номер карты
DataStr string `json:"DATA"`
Data map[string]string `json:"-"` // Дополнительные параметры платежа, переданные при создании заказа
Token string `json:"Token"` // Подпись запроса
ExpirationDate string `json:"ExpDate"` // Срок действия карты
}
func (n *Notification) GetValuesForToken() map[string]string {
var result = map[string]string{
"TerminalKey": n.TerminalKey,
"OrderId": n.OrderID,
"Success": serializeBool(n.Success),
"Status": n.Status,
"PaymentId": strconv.FormatUint(n.PaymentID, 10),
"ErrorCode": n.ErrorCode,
"Amount": strconv.FormatUint(n.Amount, 10),
"Pan": n.PAN,
"ExpDate": n.ExpirationDate,
}
if n.CardID != 0 {
result["CardId"] = strconv.FormatUint(n.CardID, 10)
}
if n.DataStr != "" {
result["DATA"] = n.DataStr
}
if n.RebillID != "" {
result["RebillId"] = n.RebillID
}
return result
}
// ParseNotification tries to parse payment state change notification body
func (c *Client) ParseNotification(requestBody io.Reader) (*Notification, error) {
bytes, err := io.ReadAll(requestBody)
if err != nil {
return nil, err
}
var notification Notification
err = json.Unmarshal(bytes, ¬ification)
if err != nil {
return nil, err
}
if c.terminalKey != notification.TerminalKey {
return nil, errors.New("invalid terminal key")
}
valuesForTokenGen := notification.GetValuesForToken()
valuesForTokenGen["Password"] = c.password
token := generateToken(valuesForTokenGen)
if token != notification.Token {
valsForTokenJSON, _ := json.Marshal(valuesForTokenGen)
return nil, fmt.Errorf("invalid token: expected %s got %s.\nValues for token: %s.\nNotification: %s", token, notification.Token, valsForTokenJSON, string(bytes))
}
if notification.DataStr != "" {
err = json.Unmarshal([]byte(notification.DataStr), ¬ification.Data)
if err != nil {
return nil, errors.New("can't unserialize DATA field: " + err.Error())
}
}
return ¬ification, nil
}
func (c *Client) GetNotificationSuccessResponse() string {
return "OK"
}