126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package currency
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
|
)
|
|
|
|
type Service struct {
|
|
repo repository.CurrencyRepository
|
|
baseCurrency domain.IntCurrency
|
|
fixerFetcher *FixerFetcher
|
|
}
|
|
|
|
func NewService(repo repository.CurrencyRepository, baseCurrency domain.IntCurrency, fixerFetcher *FixerFetcher) *Service {
|
|
return &Service{repo: repo}
|
|
}
|
|
|
|
func (s *Service) Convert(ctx context.Context, amount float64, from, to domain.IntCurrency) (float64, error) {
|
|
if from == to {
|
|
return amount, nil
|
|
}
|
|
|
|
rate, err := s.repo.GetExchangeRate(ctx, from, to)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return rate.Convert(amount)
|
|
}
|
|
|
|
func (s *Service) GetSupportedCurrencies(ctx context.Context) ([]domain.IntCurrency, error) {
|
|
return s.repo.GetSupportedCurrencies(ctx)
|
|
}
|
|
|
|
func (s *Service) UpdateRates(ctx context.Context) error {
|
|
// Implement fetching from external API (e.g., Fixer, Open Exchange Rates)
|
|
rates := map[domain.IntCurrency]map[domain.IntCurrency]float64{
|
|
domain.ETB: {
|
|
domain.USD: 0.018,
|
|
domain.EUR: 0.016,
|
|
domain.GBP: 0.014,
|
|
},
|
|
// Add other currencies...
|
|
}
|
|
|
|
for from, toRates := range rates {
|
|
for to, rate := range toRates {
|
|
err := s.repo.StoreExchangeRate(ctx, domain.IntCurrencyRate{
|
|
From: from,
|
|
To: to,
|
|
Rate: rate,
|
|
ValidUntil: time.Now().Add(24 * time.Hour), // Refresh daily
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) FetchAndStoreRates(ctx context.Context) error {
|
|
// s.logger.Info("Starting exchange rate update")
|
|
|
|
rates, err := s.fixerFetcher.FetchLatestRates(ctx, s.baseCurrency)
|
|
if err != nil {
|
|
// s.logger.Error("Failed to fetch rates", "error", err)
|
|
return fmt.Errorf("failed to fetch rates: %w", err)
|
|
}
|
|
|
|
// Convert to integer rates with precision
|
|
const precision = 6 // 1.000000
|
|
for currency, rate := range rates {
|
|
if currency == s.baseCurrency {
|
|
continue
|
|
}
|
|
|
|
intRate := domain.IntCurrencyRate{
|
|
From: s.baseCurrency,
|
|
To: currency,
|
|
Rate: rate * float64(pow10(precision)),
|
|
ValidUntil: time.Now().Add(24 * time.Hour), // Rates valid for 24 hours
|
|
}
|
|
|
|
if err := s.repo.StoreExchangeRate(ctx, intRate); err != nil {
|
|
// s.logger.Error("Failed to store rate",
|
|
// "from", s.baseCurrency,
|
|
// "to", currency,
|
|
// "error", err)
|
|
continue // Try to store other rates even if one fails
|
|
}
|
|
|
|
// Also store the inverse rate
|
|
inverseRate := domain.IntCurrencyRate{
|
|
From: currency,
|
|
To: s.baseCurrency,
|
|
Rate: (1 / rate) * float64(pow10(precision)),
|
|
ValidUntil: time.Now().Add(24 * time.Hour),
|
|
}
|
|
|
|
if err := s.repo.StoreExchangeRate(ctx, inverseRate); err != nil {
|
|
// s.logger.Error("Failed to store inverse rate",
|
|
// "from", currency,
|
|
// "to", s.baseCurrency,
|
|
// "error", err)
|
|
return fmt.Errorf("Error storing exchange rates")
|
|
}
|
|
}
|
|
|
|
// s.logger.Info("Exchange rates updated successfully")
|
|
return nil
|
|
}
|
|
|
|
func pow10(n int) int64 {
|
|
result := int64(1)
|
|
for i := 0; i < n; i++ {
|
|
result *= 10
|
|
}
|
|
return result
|
|
}
|