rimpay

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2025 License: GPL-3.0-or-later Imports: 10 Imported by: 0

Documentation

Overview

Package rimpay provides a comprehensive payment processing library for Mauritania, supporting multiple payment providers including B-PAY and MASRVI.

The library offers type-safe, provider-specific APIs with built-in validation, error handling, and retry mechanisms.

Quick Start

import (
	"context"
	"github.com/CatoSystems/rim-pay/pkg/rimpay"
	"github.com/CatoSystems/rim-pay/pkg/phone"
	"github.com/CatoSystems/rim-pay/pkg/money"
	"github.com/shopspring/decimal"
)

// Create client
config := rimpay.DefaultConfig()
config.DefaultProvider = "bpay"
client, err := rimpay.NewClient(config)

// Create payment request
phone, _ := phone.NewPhone("+22233445566")
amount := money.New(decimal.NewFromInt(10000), "MRU")

request := &rimpay.BPayPaymentRequest{
	Amount:      amount,
	PhoneNumber: phone,
	Reference:   "ORDER-12345",
	Passcode:    "1234",
}

// Process payment
response, err := client.ProcessBPayPayment(context.Background(), request)

Providers

The library supports multiple payment providers:

B-PAY: Mauritanian mobile payment provider requiring passcode authentication. MASRVI: Web-based payment provider with callback/webhook support.

Phone Numbers

Phone number validation is built-in for Mauritanian numbers:

phone, err := phone.NewPhone("+22233445566") // Valid
phone, err := phone.NewPhone("+22255667788") // Invalid (prefix 5)

Valid prefixes: 2, 3, 4 (8 digits including prefix)

Money Handling

The library uses decimal precision for accurate financial calculations:

amount := money.New(decimal.NewFromInt(10050), "MRU") // 100.50 MRU
amount := money.FromFloat64(100.50, "MRU")           // Same as above

Error Handling

Comprehensive error types are provided:

if err != nil {
	switch e := err.(type) {
	case *rimpay.ValidationError:
		// Handle validation errors
	case *rimpay.ProviderError:
		// Handle provider-specific errors
	case *rimpay.NetworkError:
		// Handle network/connectivity errors
	}
}

Configuration

Flexible configuration system supports multiple environments:

config := rimpay.DefaultConfig()
config.Environment = rimpay.EnvironmentProduction
config.Providers["bpay"] = rimpay.ProviderConfig{
	Enabled: true,
	BaseURL: "https://api.bpay.mr",
	Credentials: map[string]string{
		"username": "your_username",
		"password": "your_password",
	},
}

For more detailed examples and documentation, see: https://github.com/CatoSystems/rim-pay

Index

Constants

View Source
const (
	ProviderBPay   = "bpay"
	ProviderMasrvi = "masrvi"
)

Provider constants

View Source
const (
	ErrorCodeInvalidRequest       = types.ErrorCodeInvalidRequest
	ErrorCodeAuthenticationFailed = types.ErrorCodeAuthenticationFailed
	ErrorCodeInsufficientFunds    = types.ErrorCodeInsufficientFunds
	ErrorCodePaymentDeclined      = types.ErrorCodePaymentDeclined
	ErrorCodeNetworkError         = types.ErrorCodeNetworkError
	ErrorCodeTimeout              = types.ErrorCodeTimeout
	ErrorCodeProviderError        = types.ErrorCodeProviderError
	ErrorCodeValidationError      = types.ErrorCodeValidationError
	ErrorCodePaymentExpired       = types.ErrorCodePaymentExpired
)

Re-export constants

View Source
const (
	PaymentStatusPending   = types.PaymentStatusPending
	PaymentStatusSuccess   = types.PaymentStatusSuccess
	PaymentStatusFailed    = types.PaymentStatusFailed
	PaymentStatusCancelled = types.PaymentStatusCancelled
	PaymentStatusExpired   = types.PaymentStatusExpired

	LanguageEnglish = types.LanguageEnglish
	LanguageFrench  = types.LanguageFrench
	LanguageArabic  = types.LanguageArabic
)

Re-export constants

Variables

View Source
var (
	NewPaymentError    = types.NewPaymentError
	NewValidationError = types.NewValidationError
	IsRetryableError   = types.IsRetryableError
)

Re-export constructor functions

View Source
var (
	ErrInvalidConfig        = errors.ErrInvalidConfig
	ErrInvalidRequest       = errors.ErrInvalidRequest
	ErrProviderNotFound     = errors.ErrProviderNotFound
	ErrInvalidProvider      = errors.ErrInvalidProvider
	ErrPaymentFailed        = errors.ErrPaymentFailed
	ErrAuthenticationFailed = errors.ErrAuthenticationFailed
	ErrNetworkError         = errors.ErrNetworkError
	ErrTimeout              = errors.ErrTimeout
)

Re-export common errors

View Source
var DefaultRegistry = NewProviderRegistry()

DefaultRegistry is the default global provider registry

Functions

func RegisterBPayProvider

func RegisterBPayProvider(factory func(ProviderConfig, Logger) (PaymentProvider, error))

RegisterBPayProvider registers the B-PAY provider factory

func RegisterMasrviProvider

func RegisterMasrviProvider(factory func(ProviderConfig, Logger) (PaymentProvider, error))

RegisterMasrviProvider registers the MASRVI provider factory

Types

type BPayPaymentRequest

type BPayPaymentRequest struct {
	PhoneNumber *phone.Phone           `json:"phone_number"`
	Amount      money.Money            `json:"amount"`
	Description string                 `json:"description"`
	Reference   string                 `json:"reference"`
	Passcode    string                 `json:"passcode"` // B-PAY specific: user passcode
	Metadata    map[string]interface{} `json:"metadata,omitempty"`
}

BPayPaymentRequest represents a B-PAY specific payment request

func (*BPayPaymentRequest) ToGenericRequest

func (r *BPayPaymentRequest) ToGenericRequest() *PaymentRequest

ToGenericRequest converts B-PAY request to generic payment request

func (*BPayPaymentRequest) Validate

func (r *BPayPaymentRequest) Validate() error

Validate validates the B-PAY payment request

type BPayProvider

type BPayProvider interface {
	// Name returns the provider name
	Name() string

	// IsAvailable checks if the provider is available
	IsAvailable(ctx context.Context) bool

	// ProcessBPayPayment processes a B-PAY payment
	ProcessBPayPayment(ctx context.Context, request *BPayPaymentRequest) (*PaymentResponse, error)

	// GetPaymentStatus gets payment status
	GetPaymentStatus(ctx context.Context, transactionID string) (*TransactionStatus, error)

	// ValidateConfig validates provider configuration
	ValidateConfig() error
}

BPayProvider represents the B-PAY payment provider interface

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents the main payment client

func NewClient

func NewClient(config *Config) (*Client, error)

NewClient creates a new payment client

func (*Client) AddBPayProvider

func (c *Client) AddBPayProvider(config ProviderConfig) error

AddBPayProvider adds a B-PAY provider to the client

func (*Client) AddMasrviProvider

func (c *Client) AddMasrviProvider(config ProviderConfig) error

AddMasrviProvider adds a MASRVI provider to the client

func (*Client) AddProvider

func (c *Client) AddProvider(name string, provider PaymentProvider) error

AddProvider adds a payment provider to the client

func (*Client) GetBPayProvider

func (c *Client) GetBPayProvider() (BPayProvider, error)

GetBPayProvider returns the B-PAY provider if available

func (*Client) GetMasrviProvider

func (c *Client) GetMasrviProvider() (MasrviProvider, error)

GetMasrviProvider returns the MASRVI provider if available

func (*Client) GetPaymentStatus

func (c *Client) GetPaymentStatus(ctx context.Context, transactionID string) (*TransactionStatus, error)

GetPaymentStatus retrieves payment status from the first available provider

func (*Client) HandleMasrviNotification

func (c *Client) HandleMasrviNotification(notification *MasrviNotificationData) (*TransactionStatus, error)

HandleMasrviNotification handles MASRVI webhook notifications

func (*Client) ListProviders

func (c *Client) ListProviders() []string

ListProviders returns list of available providers

func (*Client) ProcessBPayPayment

func (c *Client) ProcessBPayPayment(ctx context.Context, request *BPayPaymentRequest) (*PaymentResponse, error)

ProcessBPayPayment processes a payment using B-PAY provider

func (*Client) ProcessMasrviPayment

func (c *Client) ProcessMasrviPayment(ctx context.Context, request *MasrviPaymentRequest) (*PaymentResponse, error)

ProcessMasrviPayment processes a payment using MASRVI provider

func (*Client) ProcessPayment

func (c *Client) ProcessPayment(ctx context.Context, request *PaymentRequest) (*PaymentResponse, error)

ProcessPayment processes a payment using the generic interface (deprecated)

type Config

type Config struct {
	Environment     Environment               `json:"environment"`
	DefaultProvider string                    `json:"default_provider"`
	Providers       map[string]ProviderConfig `json:"providers"`
	HTTP            HTTPConfig                `json:"http"`
	Logging         LoggingConfig             `json:"logging"`
	Security        SecurityConfig            `json:"security"`
}

Config represents main configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns default configuration

func (*Config) GetProviderConfig

func (c *Config) GetProviderConfig(name string) (ProviderConfig, bool)

GetProviderConfig returns provider configuration

func (*Config) IsProduction

func (c *Config) IsProduction() bool

IsProduction returns true if production environment

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration

type Environment

type Environment string
const (
	// EnvironmentSandbox for testing
	EnvironmentSandbox Environment = "sandbox"
	// EnvironmentProduction for live transactions
	EnvironmentProduction Environment = "production"
)

type ErrorCode

type ErrorCode = types.ErrorCode

Re-export types from internal/types for public API

type HTTPClient

type HTTPClient interface {
	Do(req *HTTPRequest) (*HTTPResponse, error)
}

type HTTPConfig

type HTTPConfig struct {
	Timeout         time.Duration `json:"timeout"`
	MaxIdleConns    int           `json:"max_idle_conns"`
	MaxConnsPerHost int           `json:"max_conns_per_host"`
	UserAgent       string        `json:"user_agent"`
}

HTTPConfig represents HTTP configuration

type HTTPRequest

type HTTPRequest struct {
	Method  string
	URL     string
	Headers map[string]string
	Body    []byte
	Timeout time.Duration
}

HTTPRequest represents an HTTP request

type HTTPResponse

type HTTPResponse struct {
	StatusCode int
	Headers    map[string]string
	Body       []byte
}

type Language

type Language = types.Language

type Logger

type Logger interface {
	Debug(msg string, fields ...interface{})
	Info(msg string, fields ...interface{})
	Warn(msg string, fields ...interface{})
	Error(msg string, fields ...interface{})
}

type LoggingConfig

type LoggingConfig struct {
	Level  string `json:"level"`
	Format string `json:"format"`
	Output string `json:"output"`
}

LoggingConfig represents logging configuration

type MasrviNotificationData

type MasrviNotificationData struct {
	TransactionID string                 `json:"transaction_id"`
	Status        string                 `json:"status"`
	Reference     string                 `json:"reference"`
	Amount        money.Money            `json:"amount"`
	PhoneNumber   string                 `json:"phone_number"`
	Timestamp     string                 `json:"timestamp"`
	Data          map[string]interface{} `json:"data,omitempty"`
}

MasrviNotificationData represents MASRVI webhook notification

type MasrviPaymentRequest

type MasrviPaymentRequest struct {
	PhoneNumber *phone.Phone           `json:"phone_number"`
	Amount      money.Money            `json:"amount"`
	Description string                 `json:"description"`
	Reference   string                 `json:"reference"`
	CallbackURL string                 `json:"callback_url"` // MASRVI specific: webhook URL
	ReturnURL   string                 `json:"return_url"`   // MASRVI specific: return URL after payment
	Metadata    map[string]interface{} `json:"metadata,omitempty"`
}

MasrviPaymentRequest represents a MASRVI specific payment request

func (*MasrviPaymentRequest) ToGenericRequest

func (r *MasrviPaymentRequest) ToGenericRequest() *PaymentRequest

ToGenericRequest converts MASRVI request to generic payment request

func (*MasrviPaymentRequest) Validate

func (r *MasrviPaymentRequest) Validate() error

Validate validates the MASRVI payment request

type MasrviProvider

type MasrviProvider interface {
	// Name returns the provider name
	Name() string

	// IsAvailable checks if the provider is available
	IsAvailable(ctx context.Context) bool

	// ProcessPayment processes a MASRVI payment
	ProcessMasrviPayment(ctx context.Context, request *MasrviPaymentRequest) (*PaymentResponse, error)

	// GetPaymentStatus gets payment status (note: MASRVI uses webhooks)
	GetPaymentStatus(ctx context.Context, transactionID string) (*TransactionStatus, error)

	// HandleNotification handles MASRVI webhook notifications
	HandleNotification(notification *MasrviNotificationData) (*TransactionStatus, error)

	// ValidateConfig validates provider configuration
	ValidateConfig() error
}

MasrviProvider represents the MASRVI payment provider interface

type PaymentError

type PaymentError = types.PaymentError

type PaymentProvider

type PaymentProvider interface {
	// Name returns the provider name
	Name() string

	// IsAvailable checks if the provider is available
	IsAvailable(ctx context.Context) bool

	// ProcessPayment processes a payment
	ProcessPayment(ctx context.Context, request *PaymentRequest) (*PaymentResponse, error)

	// GetPaymentStatus gets payment status
	GetPaymentStatus(ctx context.Context, transactionID string) (*TransactionStatus, error)

	// ValidateConfig validates provider configuration
	ValidateConfig() error
}

type PaymentRequest

type PaymentRequest = types.PaymentRequest

type PaymentResponse

type PaymentResponse = types.PaymentResponse

type PaymentStatus

type PaymentStatus = types.PaymentStatus

Re-export types from internal/types for public API

type ProviderConfig

type ProviderConfig struct {
	Enabled     bool                   `json:"enabled"`
	BaseURL     string                 `json:"base_url"`
	Credentials map[string]string      `json:"credentials"`
	Timeout     time.Duration          `json:"timeout"`
	Options     map[string]interface{} `json:"options"`
}

ProviderConfig represents provider configuration

type ProviderFactory

type ProviderFactory func(config ProviderConfig, logger Logger) (PaymentProvider, error)

ProviderFactory creates payment providers

type ProviderRegistry

type ProviderRegistry struct {
	// contains filtered or unexported fields
}

ProviderRegistry manages payment provider factories

func NewProviderRegistry

func NewProviderRegistry() *ProviderRegistry

NewProviderRegistry creates a new provider registry

func (*ProviderRegistry) Create

func (r *ProviderRegistry) Create(name string, config ProviderConfig, logger Logger) (PaymentProvider, error)

Create creates a provider instance

func (*ProviderRegistry) GetRegisteredProviders

func (r *ProviderRegistry) GetRegisteredProviders() []string

GetRegisteredProviders returns list of registered provider names

func (*ProviderRegistry) Register

func (r *ProviderRegistry) Register(name string, factory ProviderFactory)

Register registers a provider factory

type SecurityConfig

type SecurityConfig struct {
	EncryptionKey string        `json:"encryption_key"`
	SigningKey    string        `json:"signing_key"`
	TokenTTL      time.Duration `json:"token_ttl"`
}

SecurityConfig represents security configuration

type StatusEvent

type StatusEvent struct {
	Status    PaymentStatus          `json:"status"`
	Timestamp time.Time              `json:"timestamp"`
	Message   string                 `json:"message,omitempty"`
	Metadata  map[string]interface{} `json:"metadata,omitempty"`
}

StatusEvent represents status change event

type TransactionStatus

type TransactionStatus struct {
	TransactionID     string                 `json:"transaction_id"`
	Status            PaymentStatus          `json:"status"`
	Amount            money.Money            `json:"amount,omitempty"`
	Reference         string                 `json:"reference"`
	ProviderReference string                 `json:"provider_reference,omitempty"`
	Message           string                 `json:"message,omitempty"`
	LastUpdated       time.Time              `json:"last_updated"`
	Events            []StatusEvent          `json:"events,omitempty"`
	ProviderData      map[string]interface{} `json:"provider_data,omitempty"`
}

func (*TransactionStatus) AddEvent

func (ts *TransactionStatus) AddEvent(status PaymentStatus, message string)

AddEvent adds a status event

func (*TransactionStatus) GetLatestEvent

func (ts *TransactionStatus) GetLatestEvent() *StatusEvent

GetLatestEvent returns the most recent status event

func (*TransactionStatus) IsCompleted

func (ts *TransactionStatus) IsCompleted() bool

IsCompleted returns true if transaction is completed

func (*TransactionStatus) IsSuccessful

func (ts *TransactionStatus) IsSuccessful() bool

IsSuccessful returns true if transaction was successful

type Validator

type Validator interface {
	ValidatePaymentRequest(request *PaymentRequest) error
	ValidateAmount(amount money.Money) error
	ValidatePhoneNumber(phone string) error
}

Validator defines validation interface

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL