Skip to content

Commit f3dcd3b

Browse files
committed
1 parent 3362219 commit f3dcd3b

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

qrcode.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package PromptPay
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strings"
7+
8+
qrcode "github.com/skip2/go-qrcode"
9+
"github.com/snksoft/crc"
10+
)
11+
12+
type Payment struct {
13+
Amount float32
14+
Country string
15+
Currency string
16+
OneTime bool
17+
Account string
18+
Version string
19+
}
20+
21+
const ID_PAYLOAD_FORMAT = "00"
22+
const ID_POI_METHOD = "01"
23+
const ID_MERCHANT_INFORMATION_BOT = "29"
24+
const ID_TRANSACTION_CURRENCY = "53"
25+
const ID_TRANSACTION_AMOUNT = "54"
26+
const ID_COUNTRY_CODE = "58"
27+
const ID_CRC = "63"
28+
29+
const PAYLOAD_FORMAT_EMV_QRCPS_MERCHANT_PRESENTED_MODE = "01"
30+
const POI_METHOD_STATIC = "11"
31+
const POI_METHOD_DYNAMIC = "12"
32+
const MERCHANT_INFORMATION_TEMPLATE_ID_GUID = "00"
33+
const BOT_ID_MERCHANT_PHONE_NUMBER = "01"
34+
const BOT_ID_MERCHANT_TAX_ID = "02"
35+
const BOT_ID_MERCHANT_EWALLET_ID = "03"
36+
const GUID_PROMPTPAY = "A000000677010111"
37+
const TRANSACTION_CURRENCY_THB = "764"
38+
const COUNTRY_CODE_TH = "TH"
39+
40+
// NewPayment initialize new payment struct with default values
41+
func NewPayment() (payment Payment) {
42+
payment = Payment{
43+
Currency: "THB",
44+
Country: COUNTRY_CODE_TH,
45+
Version: "000201",
46+
}
47+
return
48+
}
49+
50+
func f(id string, value string) string {
51+
return fmt.Sprintf("%s%02d%s", id, len(value), value)
52+
}
53+
54+
func serialize(xs []string) string {
55+
return strings.Join(xs, "")
56+
}
57+
58+
func sanitizeTarget(id string) string {
59+
regex := regexp.MustCompile(`[^0-9]`)
60+
return regex.ReplaceAllString(id, "")
61+
}
62+
63+
func formatTarget(id string) string {
64+
numbers := sanitizeTarget(id)
65+
if len(numbers) >= 13 {
66+
return numbers
67+
}
68+
regex := regexp.MustCompile(`^0`)
69+
countryCoded := regex.ReplaceAllString(id, "66")
70+
return fmt.Sprintf("%013s", countryCoded)
71+
}
72+
73+
//
74+
func formatAmount(amount float32) string {
75+
return fmt.Sprintf("%.2f", amount)
76+
}
77+
78+
func formatCrc(crcValue uint64) string {
79+
return fmt.Sprintf("%04X", crcValue)
80+
}
81+
82+
// String returns string of Promptpay QRCode
83+
func (p Payment) String() string {
84+
target := sanitizeTarget(p.Account)
85+
var targetType string
86+
switch {
87+
case len(target) >= 15:
88+
targetType = BOT_ID_MERCHANT_EWALLET_ID
89+
case len(target) >= 13:
90+
targetType = BOT_ID_MERCHANT_TAX_ID
91+
default:
92+
targetType = BOT_ID_MERCHANT_PHONE_NUMBER
93+
}
94+
95+
var data []string
96+
data = append(data, f(ID_PAYLOAD_FORMAT, PAYLOAD_FORMAT_EMV_QRCPS_MERCHANT_PRESENTED_MODE))
97+
if p.Amount != 0 {
98+
data = append(data, f(ID_POI_METHOD, POI_METHOD_DYNAMIC))
99+
} else {
100+
data = append(data, f(ID_POI_METHOD, POI_METHOD_STATIC))
101+
}
102+
merchantInfo := serialize([]string{f(MERCHANT_INFORMATION_TEMPLATE_ID_GUID, GUID_PROMPTPAY), f(targetType, formatTarget(target))})
103+
data = append(data, f(ID_MERCHANT_INFORMATION_BOT, merchantInfo))
104+
data = append(data, f(ID_COUNTRY_CODE, COUNTRY_CODE_TH))
105+
data = append(data, f(ID_TRANSACTION_CURRENCY, TRANSACTION_CURRENCY_THB))
106+
data = append(data, f(ID_PAYLOAD_FORMAT, PAYLOAD_FORMAT_EMV_QRCPS_MERCHANT_PRESENTED_MODE))
107+
if p.Amount != 0 {
108+
data = append(data, f(ID_TRANSACTION_AMOUNT, formatAmount(p.Amount)))
109+
}
110+
111+
dataToCrc := fmt.Sprintf("%s%s%s", serialize(data), ID_CRC, "04")
112+
crcValue := crc.CalculateCRC(crc.CCITT, []byte(dataToCrc))
113+
data = append(data, f(ID_CRC, formatCrc(crcValue)))
114+
return serialize(data)
115+
}
116+
117+
func (p *Payment) QRCode() (png []byte, err error) {
118+
png, err = qrcode.Encode(p.String(), qrcode.High, 512)
119+
return
120+
}

0 commit comments

Comments
 (0)