frankfurter/lib/provider/adapters/bot.rb
BadMark d0a43e357a
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / publish (push) Has been cancelled
CI/CD Pipeline / release (push) Has been cancelled
up
2026-05-21 01:38:14 -06:00

68 lines
1.9 KiB
Ruby

# frozen_string_literal: true
require "json"
require "net/http"
require "provider/adapters/adapter"
class Provider
module Adapters
# Bank of Thailand. Fetches daily average commercial bank exchange rates
# for 19 currencies against the Thai baht (THB). Uses mid_rate (midpoint
# of buying transfer and selling). Some currencies are quoted per 100 or
# 1,000 units — the adapter normalises to per-unit rates.
# Requires BOT_API_KEY environment variable.
class BOT < Adapter
BASE_URL = "https://gateway.api.bot.or.th/Stat-ExchangeRate/v2/DAILY_AVG_EXG_RATE/"
class << self
def api_key = ENV["BOT_API_KEY"] || raise(Adapter::Unavailable, "no API key")
def backfill_range = 30 # API enforces max 31-day period per request
end
def fetch(after: nil, upto: nil)
uri = URI(BASE_URL)
uri.query = URI.encode_www_form(
start_period: after.strftime("%Y-%m-%d"),
end_period: (upto || Date.today).strftime("%Y-%m-%d"),
)
response = Net::HTTP.get_response(uri, {
"Authorization" => self.class.api_key,
"Accept" => "application/json",
})
parse(response.body)
end
def parse(body)
data = JSON.parse(body).dig("result", "data", "data_detail")
return [] unless data
data.filter_map do |record|
mid = record["mid_rate"]
next if mid.nil? || mid.to_s.empty?
rate = Float(mid)
next if rate.zero?
currency = record["currency_id"]
unit = extract_unit(record["currency_name_eng"])
rate /= unit if unit > 1
{ date: Date.parse(record["period"]), base: currency, quote: "THB", rate: }
end
end
private
def extract_unit(name)
case name
when /\(100 /i then 100
when /\(1,000 /i then 1_000
else 1
end
end
end
end
end