refactor: Add ExchangeRateService interface and format currency types with consistent alignment

- Add ExchangeRateService interface with GetExchangeRate, ConvertAmount, GetRateHistory, UpdateExchangeRate, GetSupportedCurrencies, ValidateCurrencyPair, and RefreshRates methods
- Add CurrencyRevenue struct with currency and revenue fields
- Add TransactionTypeStats struct with type, count, amount, and currency fields
- Align struct field tags consistently across Currency, ExchangeRate, Transaction, and request/response types
This commit is contained in:
nutcas3
2026-05-02 01:22:37 +03:00
parent 295649bcea
commit a31344714e
2 changed files with 108 additions and 83 deletions
@@ -39,6 +39,17 @@ type ExchangeRateProvider interface {
RefreshRates(ctx context.Context) error RefreshRates(ctx context.Context) error
} }
// ExchangeRateService defines the interface for exchange rate operations
type ExchangeRateService interface {
GetExchangeRate(ctx context.Context, fromCurrency, toCurrency string) (*ExchangeRate, error)
ConvertAmount(ctx context.Context, amount float64, fromCurrency, toCurrency string) (*CurrencyConversionResponse, error)
GetRateHistory(ctx context.Context, fromCurrency, toCurrency string, days int) ([]*ExchangeRate, error)
UpdateExchangeRate(ctx context.Context, rate *ExchangeRate) error
GetSupportedCurrencies(ctx context.Context) ([]*Currency, error)
ValidateCurrencyPair(ctx context.Context, fromCurrency, toCurrency string) error
RefreshRates(ctx context.Context) error
}
// BillingService defines the interface for multi-currency billing operations // BillingService defines the interface for multi-currency billing operations
type BillingService interface { type BillingService interface {
ProcessBilling(ctx context.Context, req *BillingRequest) (*BillingResponse, error) ProcessBilling(ctx context.Context, req *BillingRequest) (*BillingResponse, error)
@@ -6,11 +6,11 @@ import (
// Currency represents a currency with its properties // Currency represents a currency with its properties
type Currency struct { type Currency struct {
Code string `json:"code" db:"code"` // ISO 4217 currency code (USD, EUR, etc.) Code string `json:"code" db:"code"` // ISO 4217 currency code (USD, EUR, etc.)
Name string `json:"name" db:"name"` // Full currency name Name string `json:"name" db:"name"` // Full currency name
Symbol string `json:"symbol" db:"symbol"` // Currency symbol ($, €, etc.) Symbol string `json:"symbol" db:"symbol"` // Currency symbol ($, €, etc.)
DecimalPlaces int `json:"decimal_places" db:"decimal_places"` // Number of decimal places DecimalPlaces int `json:"decimal_places" db:"decimal_places"` // Number of decimal places
IsActive bool `json:"is_active" db:"is_active"` // Whether currency is active IsActive bool `json:"is_active" db:"is_active"` // Whether currency is active
SupportedRegions []string `json:"supported_regions" db:"supported_regions"` // Supported regions/countries SupportedRegions []string `json:"supported_regions" db:"supported_regions"` // Supported regions/countries
CreatedAt time.Time `json:"created_at" db:"created_at"` CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
@@ -18,46 +18,46 @@ type Currency struct {
// ExchangeRate represents an exchange rate between two currencies // ExchangeRate represents an exchange rate between two currencies
type ExchangeRate struct { type ExchangeRate struct {
ID string `json:"id" db:"id"` ID string `json:"id" db:"id"`
FromCurrency string `json:"from_currency" db:"from_currency"` FromCurrency string `json:"from_currency" db:"from_currency"`
ToCurrency string `json:"to_currency" db:"to_currency"` ToCurrency string `json:"to_currency" db:"to_currency"`
Rate float64 `json:"rate" db:"rate"` // Exchange rate (1 FromCurrency = Rate ToCurrency) Rate float64 `json:"rate" db:"rate"` // Exchange rate (1 FromCurrency = Rate ToCurrency)
Source string `json:"source" db:"source"` // Data source (ECB, FED, etc.) Source string `json:"source" db:"source"` // Data source (ECB, FED, etc.)
ValidFrom time.Time `json:"valid_from" db:"valid_from"` // When rate becomes valid ValidFrom time.Time `json:"valid_from" db:"valid_from"` // When rate becomes valid
ValidTo *time.Time `json:"valid_to,omitempty" db:"valid_to"` // When rate expires (optional) ValidTo *time.Time `json:"valid_to,omitempty" db:"valid_to"` // When rate expires (optional)
IsActive bool `json:"is_active" db:"is_active"` // Whether rate is currently active IsActive bool `json:"is_active" db:"is_active"` // Whether rate is currently active
CreatedAt time.Time `json:"created_at" db:"created_at"` CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
} }
// Transaction represents a financial transaction in multi-currency context // Transaction represents a financial transaction in multi-currency context
type Transaction struct { type Transaction struct {
ID string `json:"id" db:"id"` ID string `json:"id" db:"id"`
ProfileID string `json:"profile_id" db:"profile_id"` ProfileID string `json:"profile_id" db:"profile_id"`
SubscriptionID string `json:"subscription_id" db:"subscription_id"` SubscriptionID string `json:"subscription_id" db:"subscription_id"`
Type TransactionType `json:"type" db:"type"` Type TransactionType `json:"type" db:"type"`
Amount float64 `json:"amount" db:"amount"` Amount float64 `json:"amount" db:"amount"`
Currency string `json:"currency" db:"currency"` Currency string `json:"currency" db:"currency"`
BaseAmount float64 `json:"base_amount" db:"base_amount"` // Amount in base currency (USD) BaseAmount float64 `json:"base_amount" db:"base_amount"` // Amount in base currency (USD)
BaseCurrency string `json:"base_currency" db:"base_currency"` // Base currency for reporting BaseCurrency string `json:"base_currency" db:"base_currency"` // Base currency for reporting
ExchangeRate float64 `json:"exchange_rate" db:"exchange_rate"` // Rate used for conversion ExchangeRate float64 `json:"exchange_rate" db:"exchange_rate"` // Rate used for conversion
Description string `json:"description" db:"description"` Description string `json:"description" db:"description"`
Status TransactionStatus `json:"status" db:"status"` Status TransactionStatus `json:"status" db:"status"`
Metadata map[string]interface{} `json:"metadata,omitempty" db:"metadata"` Metadata map[string]interface{} `json:"metadata,omitempty" db:"metadata"`
CreatedAt time.Time `json:"created_at" db:"created_at"` CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
} }
// TransactionType defines the type of transaction // TransactionType defines the type of transaction
type TransactionType string type TransactionType string
const ( const (
TransactionTypeSubscription TransactionType = "subscription" TransactionTypeSubscription TransactionType = "subscription"
TransactionTypeUsage TransactionType = "usage" TransactionTypeUsage TransactionType = "usage"
TransactionTypeOverage TransactionType = "overage" TransactionTypeOverage TransactionType = "overage"
TransactionTypeRefund TransactionType = "refund" TransactionTypeRefund TransactionType = "refund"
TransactionTypeAdjustment TransactionType = "adjustment" TransactionTypeAdjustment TransactionType = "adjustment"
TransactionTypeDiscount TransactionType = "discount" TransactionTypeDiscount TransactionType = "discount"
) )
// TransactionStatus defines the status of a transaction // TransactionStatus defines the status of a transaction
@@ -72,78 +72,92 @@ const (
// CurrencyFilter defines filtering options for currency queries // CurrencyFilter defines filtering options for currency queries
type CurrencyFilter struct { type CurrencyFilter struct {
IsActive *bool `json:"is_active,omitempty"` IsActive *bool `json:"is_active,omitempty"`
Region string `json:"region,omitempty"` Region string `json:"region,omitempty"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
SortBy string `json:"sort_by,omitempty"`
SortOrder string `json:"sort_order,omitempty"`
}
// ExchangeRateFilter defines filtering options for exchange rate queries
type ExchangeRateFilter struct {
FromCurrency string `json:"from_currency,omitempty"`
ToCurrency string `json:"to_currency,omitempty"`
Source string `json:"source,omitempty"`
IsValid *bool `json:"is_valid,omitempty"`
Limit int `json:"limit,omitempty"` Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"` Offset int `json:"offset,omitempty"`
SortBy string `json:"sort_by,omitempty"` SortBy string `json:"sort_by,omitempty"`
SortOrder string `json:"sort_order,omitempty"` SortOrder string `json:"sort_order,omitempty"`
} }
// ExchangeRateFilter defines filtering options for exchange rate queries
type ExchangeRateFilter struct {
FromCurrency string `json:"from_currency,omitempty"`
ToCurrency string `json:"to_currency,omitempty"`
Source string `json:"source,omitempty"`
IsValid *bool `json:"is_valid,omitempty"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
SortBy string `json:"sort_by,omitempty"`
SortOrder string `json:"sort_order,omitempty"`
}
// TransactionFilter defines filtering options for transaction queries // TransactionFilter defines filtering options for transaction queries
type TransactionFilter struct { type TransactionFilter struct {
ProfileID string `json:"profile_id,omitempty"` ProfileID string `json:"profile_id,omitempty"`
SubscriptionID string `json:"subscription_id,omitempty"` SubscriptionID string `json:"subscription_id,omitempty"`
Type TransactionType `json:"type,omitempty"` Type TransactionType `json:"type,omitempty"`
Status TransactionStatus `json:"status,omitempty"` Status TransactionStatus `json:"status,omitempty"`
Currency string `json:"currency,omitempty"` Currency string `json:"currency,omitempty"`
FromDate *time.Time `json:"from_date,omitempty"` FromDate *time.Time `json:"from_date,omitempty"`
ToDate *time.Time `json:"to_date,omitempty"` ToDate *time.Time `json:"to_date,omitempty"`
MinAmount float64 `json:"min_amount,omitempty"` MinAmount float64 `json:"min_amount,omitempty"`
MaxAmount float64 `json:"max_amount,omitempty"` MaxAmount float64 `json:"max_amount,omitempty"`
Limit int `json:"limit,omitempty"` Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"` Offset int `json:"offset,omitempty"`
SortBy string `json:"sort_by,omitempty"` SortBy string `json:"sort_by,omitempty"`
SortOrder string `json:"sort_order,omitempty"` SortOrder string `json:"sort_order,omitempty"`
} }
// CurrencyConversionRequest represents a request to convert an amount between currencies // CurrencyConversionRequest represents a request to convert an amount between currencies
type CurrencyConversionRequest struct { type CurrencyConversionRequest struct {
Amount float64 `json:"amount" binding:"required,min=0"` Amount float64 `json:"amount" binding:"required,min=0"`
FromCurrency string `json:"from_currency" binding:"required"` FromCurrency string `json:"from_currency" binding:"required"`
ToCurrency string `json:"to_currency" binding:"required"` ToCurrency string `json:"to_currency" binding:"required"`
} }
// CurrencyConversionResponse represents the response from currency conversion // CurrencyConversionResponse represents the response from currency conversion
type CurrencyConversionResponse struct { type CurrencyConversionResponse struct {
OriginalAmount float64 `json:"original_amount"` OriginalAmount float64 `json:"original_amount"`
OriginalCurrency string `json:"original_currency"` OriginalCurrency string `json:"original_currency"`
ConvertedAmount float64 `json:"converted_amount"` ConvertedAmount float64 `json:"converted_amount"`
ConvertedCurrency string `json:"converted_currency"` ConvertedCurrency string `json:"converted_currency"`
ExchangeRate float64 `json:"exchange_rate"` ExchangeRate float64 `json:"exchange_rate"`
ConvertedAt time.Time `json:"converted_at"` ConvertedAt time.Time `json:"converted_at"`
} }
// BillingRequest represents a billing request in multi-currency context // BillingRequest represents a billing request in multi-currency context
type BillingRequest struct { type BillingRequest struct {
ProfileID string `json:"profile_id" binding:"required"` ProfileID string `json:"profile_id" binding:"required"`
SubscriptionID string `json:"subscription_id" binding:"required"` SubscriptionID string `json:"subscription_id" binding:"required"`
Amount float64 `json:"amount" binding:"required,min=0"` Amount float64 `json:"amount" binding:"required,min=0"`
Currency string `json:"currency" binding:"required"` Currency string `json:"currency" binding:"required"`
Description string `json:"description"` Description string `json:"description"`
BillingDate time.Time `json:"billing_date"` BillingDate time.Time `json:"billing_date"`
} }
// BillingResponse represents the response from billing operation // BillingResponse represents the response from billing operation
type BillingResponse struct { type BillingResponse struct {
TransactionID string `json:"transaction_id"` TransactionID string `json:"transaction_id"`
Amount float64 `json:"amount"` Amount float64 `json:"amount"`
Currency string `json:"currency"` Currency string `json:"currency"`
BaseAmount float64 `json:"base_amount"` BaseAmount float64 `json:"base_amount"`
BaseCurrency string `json:"base_currency"` BaseCurrency string `json:"base_currency"`
ExchangeRate float64 `json:"exchange_rate"` ExchangeRate float64 `json:"exchange_rate"`
Status string `json:"status"` Status string `json:"status"`
ProcessedAt time.Time `json:"processed_at"` ProcessedAt time.Time `json:"processed_at"`
}
// CurrencyRevenue represents revenue for a specific currency
type CurrencyRevenue struct {
Currency string `json:"currency"`
Revenue float64 `json:"revenue"`
}
// TransactionTypeStats represents statistics for a transaction type
type TransactionTypeStats struct {
Type TransactionType `json:"type"`
Count int `json:"count"`
Amount float64 `json:"amount"`
Currency string `json:"currency"`
} }