A README.md => README.md +1 -0
@@ 0,0 1,1 @@
+# GoPay's Go SDK for Payments REST API
M gopay.go => gopay.go +17 -2
@@ 4,7 4,9 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "log"
"net/http"
+ "net/http/httputil"
"time"
)
@@ 50,7 52,7 @@ func (c *Client) addAuthorization(req *http.Request) {
req.Header.Set("Authorization", "Bearer "+c.token.AccessToken)
}
-func (c *Client) CreatePayment(p Payment) (interface{}, error) {
+func (c *Client) CreatePayment(p *Payment) (*PaymentResp, error) {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(p); err != nil {
return nil, err
@@ 62,11 64,24 @@ func (c *Client) CreatePayment(p Payment) (interface{}, error) {
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
c.addAuthorization(req)
+ data, _ := httputil.DumpRequest(req, true)
+ log.Println(string(data))
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
+ data, _ = httputil.DumpResponse(resp, true)
+ log.Println(string(data))
if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("create payment response status: %s", resp.Status)
+ var errorResp ErrorResp
+ if err := json.NewDecoder(resp.Body).Decode(&errorResp); err != nil {
+ return nil, err
+ }
+ return nil, fmt.Errorf("create payment response status: %s\n%w", resp.Status, errorResp)
}
+ var paymentResp PaymentResp
+ if err := json.NewDecoder(resp.Body).Decode(&paymentResp); err != nil {
+ return nil, fmt.Errorf("create payment - decoding response: %w", err)
+ }
+ return &paymentResp, nil
}
M gopay_test.go => gopay_test.go +60 -2
@@ 8,7 8,7 @@ import (
func TestLogin(t *testing.T) {
client, err := Login("1061399163", "stDTmVXF")
if err != nil {
- t.Fatal()
+ t.Fatal(err)
}
log.Println(client.token)
}
@@ 18,5 18,63 @@ func TestCreatePayment(t *testing.T) {
if err != nil {
t.Fatal()
}
- client.CreatePayment()
+ payment := &Payment{
+ Payer: Payer{
+ AllowedPaymentInstruments: []PaymentInstrument{
+ PaymentInstrumentPaymentCard,
+ PaymentInstrumentBankAccount,
+ },
+ DefaultPaymentInstrument: PaymentInstrumentPaymentCard,
+ AllowedSwifts: []Swift{
+ SwiftFIOBCZPP,
+ SwiftBREXCZPP,
+ },
+ DefaultSwift: SwiftFIOBCZPP,
+ Contact: Contact{
+ FirstName: "Zbyněk",
+ LastName: "Žák",
+ Email: "test@test.cz",
+ PhoneNumber: "+420777456123",
+ City: "České Budějovice",
+ Street: "Planá 67",
+ PostalCode: "37301",
+ CountryCode: "CZE",
+ },
+ },
+ Target: Target{
+ Type: "ACCOUNT",
+ Goid: 8123456789,
+ },
+ Items: []Item{
+ {
+ Type: TypeDISCOUNT,
+ Name: "Obuv",
+ Amount: 119990,
+ Count: 1,
+ VatRate: 21,
+ Ean: 1234567890123,
+ ProductURL: "https://www.eshop.cz/boty/lodicky",
+ },
+ },
+ Amount: 119990,
+ Currency: CurrencyCZK,
+ OrderNumber: "OBJ20200825",
+ OrderDescription: "Obuv",
+ Lang: LangCS,
+ Callback: Callback{
+ ReturnURL: "https://www.example.com/return",
+ NotificationURL: "https://www.example.com/notify",
+ },
+ AdditionalParams: []AdditionalParam{
+ {
+ Name: "invoicenumber",
+ Value: "2015001003",
+ },
+ },
+ }
+ resp, err := client.CreatePayment(payment)
+ if err != nil {
+ t.Fatal(err)
+ }
+ log.Println(resp)
}
M objects.go => objects.go +226 -72
@@ 1,111 1,117 @@
package gopay
+import (
+ "fmt"
+ "strings"
+ "time"
+)
+
type Payment struct {
//Payment method settings and payer information
- Payer Payer `json:"payer"`
+ Payer Payer `json:"payer,omitempty"`
//Payee information
- Target Target `json:"target"`
+ Target Target `json:"target,omitempty"`
//Details of the payment items
- Items []Item `json:"items"`
+ Items []Item `json:"items,omitempty"`
//Payment amount in cents
- Amount int `json:"amount"`
+ Amount int `json:"amount,omitempty"`
//Payment currency
- Currency Currency `json:"currency"`
+ Currency Currency `json:"currency,omitempty"`
//Merchant’s order id, alphanumeric
- OrderNumber string `json:"order_number"`
+ OrderNumber string `json:"order_number,omitempty"`
//Order description, alphanumeric
- OrderDescription string `json:"order_description"`
+ OrderDescription string `json:"order_description,omitempty"`
//Payment gateway language
- Lang Lang `json:"lang"`
+ Lang Lang `json:"lang,omitempty"`
//Callback URL for processing of the payment result / Notification URL for processing of change of payment status
- Callback Callback `json:"callback"`
+ Callback Callback `json:"callback,omitempty"`
//Additional payment parameters
//Max items: 4
- AdditionalParams []AdditionalParam `json:"additional_params"`
+ AdditionalParams []AdditionalParam `json:"additional_params,omitempty"`
//true if the payment should be preauthorized
- Preauthorization bool `json:"preauthorization"`
+ Preauthorization bool `json:"preauthorization,omitempty"`
//Contains object describing recurrence, if the payment should be recurrent
- Recurrence Recurrence `json:"recurrence"`
+ Recurrence Recurrence `json:"recurrence,omitempty"`
}
type Payer struct {
//Array of allowed payment methods
- Allowed_payment_instruments []PaymentInstrument `json:"allowed_payment_instruments"`
+ AllowedPaymentInstruments []PaymentInstrument `json:"allowed_payment_instruments,omitempty"`
//Preferred payment method
- DefaultPaymentInstrument PaymentInstrument `json:"default_payment_instrument"`
+ DefaultPaymentInstrument PaymentInstrument `json:"default_payment_instrument,omitempty"`
//Array of allowed bank codes
- Allowed_swifts []Swift `json:"allowed_swifts"`
+ AllowedSwifts []Swift `json:"allowed_swifts,omitempty"`
//Preferred bank if default_payment_instrument is set to BANK_ACCOUNT, set by SWIFT code
- DefaultSwift Swift `json:"default_swift"`
+ DefaultSwift Swift `json:"default_swift,omitempty"`
//Customer´s data
- Contact Contact `json:"contact"`
+ Contact Contact `json:"contact,omitempty"`
//Bank account´s information
- BankAccount BankAccount `json:"bank_account"`
+ BankAccount BankAccount `json:"bank_account,omitempty"`
//Payment card´s information
- PaymentCard PaymentCard `json:"payment_card"`
+ PaymentCard PaymentCard `json:"payment_card,omitempty"`
//PIN for identification payment purposes
- VerifyPin string `json:"verify_pin"`
+ VerifyPin string `json:"verify_pin,omitempty"`
//Token for identification payment purposes
- AllowedCardRoken string `json:"allowed_card_token"`
+ AllowedCardRoken string `json:"allowed_card_token,omitempty"`
//Email of used GoPay wallet (only for GOPAY payment method)
- Email string `json:"email"`
+ Email string `json:"email,omitempty"`
}
type Target struct {
//always ACCOUNT
- Type string `json:"type"`
+ Type string `json:"type,omitempty"`
//Unique identifier of an e-shop in the payment gateway system
//Example: 8123456789
- Goid int `json:"goid"`
+ Goid int `json:"goid,omitempty"`
}
type Item struct {
//Type of row, for registration of sales
- Type Type `json:"type"`
+ Type Type `json:"type,omitempty"`
//Product name
//Max length: 256
- Name string `json:"name"`
+ Name string `json:"name,omitempty"`
//Total price of items in cents
- Amount int `json:"amount"`
+ Amount int `json:"amount,omitempty"`
//Number of items
//Min: 1
- Count int `json:"count"`
+ Count int `json:"count,omitempty"`
//VAT rate
//Min: 0
//Max: 100
- VatRate int `json:"vat_rate"`
+ VatRate int `json:"vat_rate,omitempty"`
//EAN code of the product
- Ean int `json:"ean"`
+ Ean int `json:"ean,omitempty"`
//URL address of the product
//Max length: 512
- ProductURL string `json:"product_url"`
+ ProductURL string `json:"product_url,omitempty"`
}
type Currency string
@@ 147,7 153,7 @@ type Callback struct {
//URL address for sending asynchronous notification in the case of changes in the payment status (with protocol)
//Max length: 512
- NotificationURL string `json:"notification_url"`
+ NotificationURL string `json:"notification_url,omitempty"`
}
type AdditionalParam struct {
@@ 163,19 169,19 @@ type AdditionalParam struct {
type Recurrence struct {
//Time period of recurring
//Example: MONTH
- RecurrenceCycle RecurrenceCycle `json:"recurrence_cycle"`
+ RecurrenceCycle RecurrenceCycle `json:"recurrence_cycle,omitempty"`
//Recurring period of recurring payment
//Example: 12
- RecurrencePeriod int `json:"recurrence_period"`
+ RecurrencePeriod int `json:"recurrence_period,omitempty"`
//The period of validity recurring payment
//Example: 2025-12-31
- RecurrenceDateTo string `json:"recurrence_date_to"`
+ RecurrenceDateTo string `json:"recurrence_date_to,omitempty"`
//Describes state of recurring payment
//Example: STARTED
- RecurrenceState RecurrenceState `json:"recurrence_state"`
+ RecurrenceState RecurrenceState `json:"recurrence_state,omitempty"`
}
type PaymentInstrument string
@@ 254,81 260,81 @@ const (
type Contact struct {
//First name
//Max length: 256
- FirstName string `json:"first_name"`
+ FirstName string `json:"first_name,omitempty"`
//Last name
//Max length: 256
- LastName string `json:"last_name"`
+ LastName string `json:"last_name,omitempty"`
//Valid e-mail
//Max length: 128
- Email string `json:"email"`
+ Email string `json:"email,omitempty"`
//Phone number with country code
//Max length: 128
- PhoneNumber string `json:"phone_number"`
+ PhoneNumber string `json:"phone_number,omitempty"`
//City
//Max length: 128
- City string `json:"city"`
+ City string `json:"city,omitempty"`
//Street
//Max length: 128
- Street string `json:"street"`
+ Street string `json:"street,omitempty"`
//Postal code
//Max length: 16
- PostalCode string `json:"postal_code"`
+ PostalCode string `json:"postal_code,omitempty"`
//Country code ISO 3166-1 alpha-3
- CountryCode string `json:"country_code"`
+ CountryCode string `json:"country_code,omitempty"`
}
type BankAccount struct {
//International bank account number
- IBAN string `json:"iban"`
+ IBAN string `json:"iban,omitempty"`
//Business identification code (SWIFT)
- BIC string `json:"bic"`
+ BIC string `json:"bic,omitempty"`
//Bank account prefix
- Prefix string `json:"prefix"`
+ Prefix string `json:"prefix,omitempty"`
//Bank account number
- AccountNumber string `json:"account_number"`
+ AccountNumber string `json:"account_number,omitempty"`
//Bank account code
- BankCode string `json:"bank_code"`
+ BankCode string `json:"bank_code,omitempty"`
//Bank account holder name
- AccountName string `json:"account_name"`
+ AccountName string `json:"account_name,omitempty"`
//Account token of a saved account for PSD2 payments
- AccountToken string `json:"account_token"`
+ AccountToken string `json:"account_token,omitempty"`
}
type PaymentCard struct {
//Masked payment card´s number
- CardNumber string `json:"card_number"`
+ CardNumber string `json:"card_number,omitempty"`
//Expiration date
- CardExpiration string `json:"card_expiration"`
+ CardExpiration string `json:"card_expiration,omitempty"`
//Payment card´s type
- CardBrand string `json:"card_brand"`
+ CardBrand string `json:"card_brand,omitempty"`
//Country code of issuing bank
- CardIssuerCountry string `json:"card_issuer_country"`
+ CardIssuerCountry string `json:"card_issuer_country,omitempty"`
//Issuing bank
- CardIssuerBank string `json:"card_issuer_bank"`
+ CardIssuerBank string `json:"card_issuer_bank,omitempty"`
//Token for identification payment purposes
//Example: 6RuTM69kX6UUGZ6p9hyMPrTUVXmMDdkC4BNnQvQcb
- CardToken string `json:"card_token"`
+ CardToken string `json:"card_token,omitempty"`
//3D Secure authorization’s result for identification payment purposes
- Result3DS string `json:"3ds_result"`
+ Result3DS string `json:"3ds_result,omitempty"`
}
type Type string
@@ 358,41 364,41 @@ const (
type PaymentResp struct {
//Payment ID
- Id int `json:"id"`
+ Id int `json:"id,omitempty"`
//Order ID
- OrderNumber string `json:"order_number"`
+ OrderNumber string `json:"order_number,omitempty"`
//Payment status
- State State `json:"state"`
+ State State `json:"state,omitempty"`
//Amount in cents
- Amount int `json:"amount"`
+ Amount int `json:"amount,omitempty"`
//Payment currency
- Currency Currency `json:"currency"`
+ Currency Currency `json:"currency,omitempty"`
//Information about the payer and payment methods
- Payer Payer `json:"payer"`
+ Payer Payer `json:"payer,omitempty"`
//Payee information
- Target Target `json:"target"`
+ Target Target `json:"target,omitempty"`
//Additional parameters
- AdditionalParams []AdditionalParam `json:"additional_params"`
+ AdditionalParams []AdditionalParam `json:"additional_params,omitempty"`
//Payment gateway language
- Lang Lang `json:"lang"`
+ Lang Lang `json:"lang,omitempty"`
//Descibes recurrence if the payment is recurrent
- Recurrence Recurrence `json:"recurrence"`
+ Recurrence Recurrence `json:"recurrence,omitempty"`
//Describes preauthorization if the payment is preauthorized
- Preauthorization Preauthorization `json:"preauthorization"`
+ Preauthorization Preauthorization `json:"preauthorization,omitempty"`
//URL for initiation of the payment gate
//Example: https://gw.sandbox.gopay.com/gw/v3/bCcvmwTKK5hrJx2aGG8ZnFyBJhAvF
- GwURL string `json:"gw_url"`
+ GwURL string `json:"gw_url,omitempty"`
}
type State string
@@ 410,10 416,10 @@ const (
type Preauthorization struct {
//Whether the pre-authorization was established
- Requested bool `json:"requested"`
+ Requested bool `json:"requested,omitempty"`
//Payment pre-authorization status
- State PreauthorizationState `json:"state"`
+ State PreauthorizationState `json:"state,omitempty"`
}
type PreauthorizationState string
@@ 424,3 430,151 @@ const (
PreauthorizationStateCaptured PreauthorizationState = "CAPTURED" //Pre-authorion captured
PreauthorizationStateCanceled PreauthorizationState = "CANCELED" //Pre-authorization canceled
)
+
+type ErrorResp struct {
+ DateIssued time.Time
+ Errors []Error
+}
+
+func (er ErrorResp) Error() string {
+ errors := make([]string, len(er.Errors))
+ for i := 1; i < len(er.Errors); i++ {
+ errors[i] = er.Errors[i].Error()
+ }
+ return strings.Join(errors, ", ")
+}
+
+type Error struct {
+ Scope ErrorScope //Error range
+ Field string //Which parameter is affected by the error, unless it is a global error
+ Message string //Localized message. Localization based on Accept-Language in the header. It is set to en-US by default.
+ Description string //Technical description of the error
+ ErrorCode ErrorCode //Numeric designation of the error type
+ ErrorName string //Code designation of the error type
+}
+
+func (e Error) Error() string {
+ return fmt.Sprintf(
+ "Scope: %s\nField: %s\nMessage: %s\nDescription: %s\nErrorCode: %s\nErrorName: %s",
+ e.Scope,
+ e.Field,
+ e.Message,
+ e.Description,
+ e.ErrorCode,
+ e.ErrorName,
+ )
+}
+
+type ErrorScope string
+
+const (
+ ErrorScopeF ErrorScope = "F" //The error concerns a specific parameter
+ ErrorScopeG ErrorScope = "G" //Global error
+)
+
+type ErrorCode int
+
+const (
+ ErrorCode100 ErrorCode = 100 //System Error
+ ErrorCode110 ErrorCode = 110 //Compulsory
+ ErrorCode111 ErrorCode = 111 //Wrong format
+ ErrorCode112 ErrorCode = 112 //Already exists
+ ErrorCode113 ErrorCode = 113 //Cannot be changed
+ ErrorCode114 ErrorCode = 114 //Cannot delete
+ ErrorCode115 ErrorCode = 115 //Ambiguous
+ ErrorCode116 ErrorCode = 116 //Invalid request
+ ErrorCode200 ErrorCode = 200 //Unauthorized access
+ ErrorCode201 ErrorCode = 201 //The method of assigning rights is not supported
+ ErrorCode202 ErrorCode = 202 //Wrong access data
+ ErrorCode203 ErrorCode = 203 //PIN access has been disabled
+ ErrorCode301 ErrorCode = 301 //Unable to create payment
+ ErrorCode302 ErrorCode = 302 //Payment cannot be made
+ ErrorCode303 ErrorCode = 303 //Payment in wrong condition
+ ErrorCode304 ErrorCode = 304 //Payment not found
+ ErrorCode305 ErrorCode = 305 //E-shop has been deactivated
+ ErrorCode321 ErrorCode = 321 //The payee cannot accept the payment
+ ErrorCode330 ErrorCode = 330 //Payment cannot be refunded
+ ErrorCode331 ErrorCode = 331 //Payment cannot be refunded
+ ErrorCode332 ErrorCode = 332 //Wrong amount
+ ErrorCode333 ErrorCode = 333 //Lack of money in the account
+ ErrorCode340 ErrorCode = 340 //Recurring payment failed
+ ErrorCode341 ErrorCode = 341 //Recurring payment is not supported
+ ErrorCode342 ErrorCode = 342 //Payment recurrence stopped
+ ErrorCode343 ErrorCode = 343 //Time limit for recurring payments exceeded
+ ErrorCode350 ErrorCode = 350 //Payment hold failed
+ ErrorCode351 ErrorCode = 351 //Payment has already been canceled
+ ErrorCode352 ErrorCode = 352 //Revocation revocation failed
+ ErrorCode353 ErrorCode = 353 //Pre-authorization canceled
+ ErrorCode360 ErrorCode = 360 //The sum of the amounts of the order items does not match the payment amount
+ ErrorCode394 ErrorCode = 394 //Account not found
+)
+
+func (e ErrorCode) String() string {
+ switch e {
+ case ErrorCode100:
+ return "System Error"
+ case ErrorCode110:
+ return "Compulsory"
+ case ErrorCode111:
+ return "Wrong format"
+ case ErrorCode112:
+ return "Already exists"
+ case ErrorCode113:
+ return "Cannot be changed"
+ case ErrorCode114:
+ return "Cannot delete"
+ case ErrorCode115:
+ return "Ambiguous"
+ case ErrorCode116:
+ return "Invalid request"
+ case ErrorCode200:
+ return "Unauthorized access"
+ case ErrorCode201:
+ return "The method of assigning rights is not supported"
+ case ErrorCode202:
+ return "Wrong access data"
+ case ErrorCode203:
+ return "PIN access has been disabled"
+ case ErrorCode301:
+ return "Unable to create payment"
+ case ErrorCode302:
+ return "Payment cannot be made"
+ case ErrorCode303:
+ return "Payment in wrong condition"
+ case ErrorCode304:
+ return "Payment not found"
+ case ErrorCode305:
+ return "E-shop has been deactivated"
+ case ErrorCode321:
+ return "The payee cannot accept the payment"
+ case ErrorCode330:
+ return "Payment cannot be refunded"
+ case ErrorCode331:
+ return "Payment cannot be refunded"
+ case ErrorCode332:
+ return "Wrong amount"
+ case ErrorCode333:
+ return "Lack of money in the account"
+ case ErrorCode340:
+ return "Recurring payment failed"
+ case ErrorCode341:
+ return "Recurring payment is not supported"
+ case ErrorCode342:
+ return "Payment recurrence stopped"
+ case ErrorCode343:
+ return "Time limit for recurring payments exceeded"
+ case ErrorCode350:
+ return "Payment hold failed"
+ case ErrorCode351:
+ return "Payment has already been canceled"
+ case ErrorCode352:
+ return "Revocation revocation failed"
+ case ErrorCode353:
+ return "Pre-authorization canceled"
+ case ErrorCode360:
+ return "The sum of the amounts of the order items does not match the payment amount"
+ case ErrorCode394:
+ return "Account not found"
+ }
+ return fmt.Sprintf("%d", e)
+}