164 lines
4.5 KiB
Go
164 lines
4.5 KiB
Go
/*
|
|
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
package redsys
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/jackc/pgtype"
|
|
"golang.org/x/text/language"
|
|
"time"
|
|
|
|
"dev.tandem.ws/tandem/camper/pkg/auth"
|
|
"dev.tandem.ws/tandem/camper/pkg/database"
|
|
)
|
|
|
|
type TransactionType int
|
|
type ResponseCode int
|
|
|
|
const (
|
|
TransactionTypeCharge TransactionType = 0
|
|
TransactionTypeRefund TransactionType = 3
|
|
TransactionTypePreauth TransactionType = 1
|
|
TransactionTypePreauthConfirm TransactionType = 2
|
|
TransactionTypePreauthVoid TransactionType = 9
|
|
TransactionTypeSplitAuth TransactionType = 7
|
|
TransactionTypeSplitConfirm TransactionType = 8
|
|
|
|
ResponsePaymentAuthorized ResponseCode = 99
|
|
ResponseRefundAuthorized ResponseCode = 900
|
|
ResponseCancelAuthorized ResponseCode = 400
|
|
ResponseCardExpired ResponseCode = 101
|
|
ResponseCardException ResponseCode = 102
|
|
ResponseTooManyPINAttempts ResponseCode = 106
|
|
ResponseCardNotEffective ResponseCode = 125
|
|
ResponseIncorrectSecureCode ResponseCode = 129
|
|
ResponseDenied ResponseCode = 172
|
|
)
|
|
|
|
type Request struct {
|
|
TransactionType TransactionType
|
|
Amount string
|
|
OrderNumber string
|
|
Product string
|
|
CardHolder string
|
|
SuccessURL string
|
|
FailureURL string
|
|
NotificationURL string
|
|
ConsumerLanguage language.Tag
|
|
}
|
|
|
|
func (req Request) Sign(ctx context.Context, conn *database.Conn, company *auth.Company) (*SignedRequest, error) {
|
|
row := conn.QueryRow(ctx, "select redsys_sign_request($1, $2)", company.ID, req)
|
|
signed := &SignedRequest{}
|
|
if err := row.Scan(&signed); err != nil {
|
|
return nil, err
|
|
}
|
|
return signed, nil
|
|
}
|
|
|
|
func (req Request) EncodeText(ci *pgtype.ConnInfo, dst []byte) ([]byte, error) {
|
|
typeName := database.RedsysRequestTypeName
|
|
dt, ok := ci.DataTypeForName(typeName)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unable to find oid for type name %v", typeName)
|
|
}
|
|
values := []interface{}{
|
|
req.TransactionType,
|
|
req.Amount,
|
|
req.OrderNumber,
|
|
req.Product,
|
|
req.CardHolder,
|
|
req.SuccessURL,
|
|
req.FailureURL,
|
|
req.NotificationURL,
|
|
req.ConsumerLanguage,
|
|
}
|
|
ct := pgtype.NewValue(dt.Value).(*pgtype.CompositeType)
|
|
if err := ct.Set(values); err != nil {
|
|
return nil, err
|
|
}
|
|
return ct.EncodeText(ci, dst)
|
|
}
|
|
|
|
type SignedRequest struct {
|
|
MerchantParameters string
|
|
Signature string
|
|
SignatureVersion string
|
|
}
|
|
|
|
func (dst *SignedRequest) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
|
typeName := database.RedsysSignedRequestTypeName
|
|
dt, ok := ci.DataTypeForName(typeName)
|
|
if !ok {
|
|
return fmt.Errorf("unable to find oid for type name %v", typeName)
|
|
}
|
|
ct := pgtype.NewValue(dt.Value).(*pgtype.CompositeType)
|
|
if err := ct.DecodeText(ci, src); err != nil {
|
|
return err
|
|
}
|
|
return ct.AssignTo(dst)
|
|
}
|
|
|
|
type SignedResponse struct {
|
|
MerchantParameters string
|
|
Signature string
|
|
SignatureVersion string
|
|
}
|
|
|
|
func (signed SignedResponse) Decode(ctx context.Context, conn *database.Conn, company *auth.Company) (*Response, error) {
|
|
row := conn.QueryRow(ctx, "select redsys_decode_response($1, $2, $3, $4)", company.ID, signed.MerchantParameters, signed.Signature, signed.SignatureVersion)
|
|
response := &Response{}
|
|
if err := row.Scan(&response); err != nil {
|
|
return nil, err
|
|
}
|
|
return response, nil
|
|
}
|
|
|
|
type Response struct {
|
|
MerchantCode string
|
|
TerminalNumber int
|
|
ResponseCode ResponseCode
|
|
DateTime time.Time
|
|
SecurePayment bool
|
|
TransactionType TransactionType
|
|
Amount string
|
|
CurrencyCode string
|
|
OrderNumber string
|
|
AuthorizationCode string
|
|
ErrorCode string
|
|
}
|
|
|
|
func (response *Response) Process(ctx context.Context, conn *database.Conn, paymentSlug string) (string, error) {
|
|
return conn.GetText(ctx, "select process_payment_response($1, $2)", paymentSlug, response)
|
|
}
|
|
|
|
func (response *Response) EncodeBinary(ci *pgtype.ConnInfo, dst []byte) ([]byte, error) {
|
|
typeName := database.RedsysResponseTypeName
|
|
dt, ok := ci.DataTypeForName(typeName)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unable to find oid for type name %v", typeName)
|
|
}
|
|
values := []interface{}{
|
|
response.MerchantCode,
|
|
response.TerminalNumber,
|
|
response.ResponseCode,
|
|
response.DateTime,
|
|
response.SecurePayment,
|
|
response.TransactionType,
|
|
response.Amount,
|
|
response.CurrencyCode,
|
|
response.OrderNumber,
|
|
response.AuthorizationCode,
|
|
response.ErrorCode,
|
|
}
|
|
ct := pgtype.NewValue(dt.Value).(*pgtype.CompositeType)
|
|
if err := ct.Set(values); err != nil {
|
|
return nil, err
|
|
}
|
|
return ct.EncodeBinary(ci, dst)
|
|
}
|