Yimaru-BackEnd/internal/services/currency/service.go

126 lines
3.0 KiB
Go

package currency
import (
"Yimaru-Backend/internal/domain"
"Yimaru-Backend/internal/repository"
"context"
"fmt"
"time"
)
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
}