-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreceipt.go
More file actions
79 lines (72 loc) · 2.41 KB
/
receipt.go
File metadata and controls
79 lines (72 loc) · 2.41 KB
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
package mppx
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
)
// Receipt is a payment receipt returned by a server after successful payment verification.
type Receipt struct {
// Method is the payment method used (e.g. "tempo", "stripe").
Method string `json:"method"`
// Reference is a method-specific payment reference (e.g. transaction hash).
Reference string `json:"reference"`
// Status is always "success". Failures use HTTP 402 + Problem Details.
Status string `json:"status"`
// Timestamp is the RFC 3339 settlement timestamp.
Timestamp string `json:"timestamp"`
// ExternalID is an optional external reference ID echoed from the credential payload.
ExternalID string `json:"externalId,omitempty"`
}
// ReceiptParams holds parameters for creating a Receipt.
type ReceiptParams struct {
Method string
Reference string
Timestamp time.Time // defaults to time.Now() if zero
ExternalID string
}
// NewReceipt creates a Receipt. Status is always set to "success".
func NewReceipt(p ReceiptParams) Receipt {
ts := p.Timestamp
if ts.IsZero() {
ts = time.Now().UTC()
}
return Receipt{
Method: p.Method,
Reference: p.Reference,
Status: ReceiptStatusSuccess,
Timestamp: ts.Format(time.RFC3339),
ExternalID: p.ExternalID,
}
}
// SerializeReceipt serializes a Receipt to a base64url-encoded JSON string
// suitable for the Payment-Receipt response header.
func SerializeReceipt(r Receipt) string { //nolint:gocritic // Public API keeps value params for backward compatibility.
data, err := json.Marshal(r)
if err != nil {
return ""
}
return base64.RawURLEncoding.EncodeToString(data)
}
// DeserializeReceipt decodes a base64url-encoded Payment-Receipt header value.
func DeserializeReceipt(encoded string) (Receipt, error) {
data, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
return Receipt{}, fmt.Errorf("mpp: invalid base64url in receipt: %w", err)
}
var r Receipt
if err := json.Unmarshal(data, &r); err != nil {
return Receipt{}, fmt.Errorf("mpp: invalid JSON in receipt: %w", err)
}
return r, nil
}
// ExtractReceipt extracts the Receipt from an HTTP response's Payment-Receipt header.
func ExtractReceipt(resp *http.Response) (Receipt, error) {
header := resp.Header.Get(PaymentReceiptHeader)
if header == "" {
return Receipt{}, errors.New("mpp: missing " + PaymentReceiptHeader + " header")
}
return DeserializeReceipt(header)
}