forked from ebhomengo/niki
100 lines
2.8 KiB
Go
100 lines
2.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
type PaymentService struct {
|
|
repo PaymentRepository
|
|
gwFactory GatewayFactory
|
|
}
|
|
|
|
type PaymentRepository interface {
|
|
CreatePayment(ctx context.Context, p *Payment) error
|
|
CreateTransaction(ctx context.Context, t *PaymentTransaction) error
|
|
UpdateTransaction(ctx context.Context, t *PaymentTransaction) error
|
|
GetGatewayByCode(ctx context.Context, code string) (*Gateway, error)
|
|
}
|
|
|
|
type GatewayFactory interface {
|
|
GetGatewayAdapter(code string) (GatewayPort, error)
|
|
}
|
|
|
|
type GatewayPort interface {
|
|
Request(amount int64, callbackURL string, description string) (token string, redirectURL string, rawReq []byte, rawRes []byte, err error)
|
|
}
|
|
|
|
func NewPaymentService(r PaymentRepository, gwf GatewayFactory) *PaymentService {
|
|
return &PaymentService{
|
|
repo: r,
|
|
gwFactory: gwf,
|
|
}
|
|
}
|
|
|
|
func (s *PaymentService) InitiatePayment(ctx context.Context, req InitiatePaymentRequest) (*InitiatePaymentResponse, error) {
|
|
|
|
gateway, err := s.repo.GetGatewayByCode(ctx, req.GatewayCode)
|
|
if err != nil || !gateway.IsActive {
|
|
return nil, errors.New("gateway is not available")
|
|
}
|
|
|
|
payment := &Payment{
|
|
UserID: req.UserID,
|
|
PayableType: req.PayableType,
|
|
PayableID: req.PayableID,
|
|
GatewayID: gateway.ID,
|
|
TotalAmount: req.Amount,
|
|
Currency: CurrencyIRR,
|
|
Status: PaymentStatusPending,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
if err := s.repo.CreatePayment(ctx, payment); err != nil {
|
|
return nil, fmt.Errorf("failed to create payment: %w", err)
|
|
}
|
|
|
|
transaction := &PaymentTransaction{
|
|
PaymentID: payment.ID,
|
|
Type: TransactionTypeRequest,
|
|
Status: TransactionStatusPending,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
if err := s.repo.CreateTransaction(ctx, transaction); err != nil {
|
|
return nil, fmt.Errorf("failed to create initial transaction: %w", err)
|
|
}
|
|
|
|
gwAdapter, err := s.gwFactory.GetGatewayAdapter(gateway.Code)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load gateway adapter: %w", err)
|
|
}
|
|
|
|
desc := fmt.Sprintf(" پرداخت برای %s شماره %d", req.PayableType, req.PayableID)
|
|
token, redirectURL, rawReq, rawRes, gwErr := gwAdapter.Request(req.Amount, req.CallbackURL, desc)
|
|
|
|
transaction.RequestData = rawReq
|
|
transaction.ResponseData = rawRes
|
|
transaction.UpdatedAt = time.Now()
|
|
|
|
if gwErr != nil {
|
|
transaction.Status = TransactionStatusFailed
|
|
transaction.ErrorMessage = gwErr.Error()
|
|
_ = s.repo.UpdateTransaction(ctx, transaction)
|
|
return nil, fmt.Errorf("gateway request failed: %w", gwErr)
|
|
}
|
|
|
|
transaction.Status = TransactionStatusSuccess
|
|
transaction.GatewayToken = token
|
|
if err := s.repo.UpdateTransaction(ctx, transaction); err != nil {
|
|
return nil, fmt.Errorf("failed to update transaction with token: %w", err)
|
|
}
|
|
|
|
return &InitiatePaymentResponse{
|
|
PaymentID: payment.ID,
|
|
RedirectURL: redirectURL,
|
|
}, nil
|
|
}
|