forked from ebhomengo/niki
106 lines
3.1 KiB
Go
106 lines
3.1 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.gocasts.ir/ebhomengo/niki/domain/payment/entity"
|
|
)
|
|
|
|
type PaymentService struct {
|
|
paymentRepo PaymentRepo
|
|
paymentMethodRepo PaymentMethodRepo
|
|
gwFactory GatewayFactory
|
|
}
|
|
|
|
type PaymentRepo interface {
|
|
CreatePayment(ctx context.Context, p *entity.Payment) error
|
|
CreateTransaction(ctx context.Context, t *entity.PaymentTransaction) error
|
|
UpdateTransaction(ctx context.Context, t *entity.PaymentTransaction) error
|
|
}
|
|
type PaymentMethodRepo interface {
|
|
GetGatewayByCode(ctx context.Context, code string) (entity.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(pr PaymentRepo, pmr PaymentMethodRepo, gwf GatewayFactory) *PaymentService {
|
|
return &PaymentService{
|
|
paymentRepo: pr,
|
|
paymentMethodRepo: pmr,
|
|
gwFactory: gwf,
|
|
}
|
|
}
|
|
|
|
func (s *PaymentService) InitiatePayment(ctx context.Context, req InitiatePaymentRequest) (*InitiatePaymentResponse, error) {
|
|
|
|
gateway, err := s.paymentMethodRepo.GetGatewayByCode(ctx, req.GatewayCode)
|
|
if err != nil || !gateway.IsActive {
|
|
return nil, errors.New("gateway is not available")
|
|
}
|
|
|
|
payment := &entity.Payment{
|
|
UserID: req.UserID,
|
|
PayableType: req.PayableType,
|
|
PayableID: req.PayableID,
|
|
GatewayID: gateway.ID,
|
|
TotalAmount: req.Amount,
|
|
Currency: entity.CurrencyIRR,
|
|
Status: entity.PaymentStatusPending,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
if err := s.paymentRepo.CreatePayment(ctx, payment); err != nil {
|
|
return nil, fmt.Errorf("failed to create payment: %w", err)
|
|
}
|
|
|
|
transaction := &entity.PaymentTransaction{
|
|
PaymentID: payment.ID,
|
|
Type: entity.TransactionTypeRequest,
|
|
Status: entity.TransactionStatusPending,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
if err := s.paymentRepo.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 = entity.TransactionStatusFailed
|
|
transaction.ErrorMessage = gwErr.Error()
|
|
_ = s.paymentRepo.UpdateTransaction(ctx, transaction)
|
|
return nil, fmt.Errorf("gateway request failed: %w", gwErr)
|
|
}
|
|
|
|
transaction.Status = entity.TransactionStatusSuccess
|
|
transaction.GatewayToken = token
|
|
if err := s.paymentRepo.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
|
|
}
|