frankfurter/lib/provider/adapters/cba.rb

100 lines
3.1 KiB
Ruby
Raw Normal View History

2026-05-21 01:38:14 -06:00
# frozen_string_literal: true
require "net/http"
require "ox"
require "provider/adapters/adapter"
class Provider
module Adapters
# Central Bank of Armenia. Publishes daily rates for ~30 currencies against AMD.
class CBA < Adapter
URL = URI("https://api.cba.am/exchangerates.asmx")
CHUNK_SIZE = 365
TROY_OUNCE_GRAMS = 31.1035
PRECIOUS_METALS = ["XAU", "XAG"].freeze
def fetch(after: nil, upto: nil)
end_date = upto || Date.today
iso_codes = current_currency_codes
records = []
chunk_start = after
while chunk_start <= end_date
chunk_end = [chunk_start + CHUNK_SIZE - 1, end_date].min
records.concat(range(chunk_start, chunk_end, iso_codes))
chunk_start = chunk_end + 1
end
records
end
private
def current_currency_codes
response = request("ExchangeRatesLatest", <<~XML)
<ExchangeRatesLatest xmlns="http://www.cba.am/" />
XML
result = response.locate("soap:Envelope/soap:Body/ExchangeRatesLatestResponse/ExchangeRatesLatestResult").first
return "" unless result
result.locate("Rates/ExchangeRate").filter_map do |node|
node.locate("ISO").first&.text
end.join(",")
end
def range(start_date, end_date, iso_codes)
response = request("ExchangeRatesByDateRangeByISO", <<~XML)
<ExchangeRatesByDateRangeByISO xmlns="http://www.cba.am/">
<ISOCodes>#{iso_codes}</ISOCodes>
<DateFrom>#{start_date}</DateFrom>
<DateTo>#{end_date}</DateTo>
</ExchangeRatesByDateRangeByISO>
XML
response
.locate("soap:Envelope/soap:Body/ExchangeRatesByDateRangeByISOResponse/ExchangeRatesByDateRangeByISOResult/diffgr:diffgram/DocumentElement/ExchangeRatesByRange")
.filter_map do |row|
iso = row.locate("ISO").first&.text
next unless iso
{ date: Date.parse(row.locate("RateDate").first.text), base: iso, quote: "AMD", rate: extract_rate(row) }
end
end
def request(action, payload)
xml = <<~XML
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
#{payload.strip}
</soap:Body>
</soap:Envelope>
XML
Ox.load(
Net::HTTP.post(
URL,
xml,
{
"Content-Type" => "text/xml; charset=utf-8",
"SOAPAction" => "\"http://www.cba.am/#{action}\"",
},
).body,
)
end
def extract_rate(node)
iso = node.locate("ISO").first&.text
amount = Integer(node.locate("Amount").first.text)
rate = Float(node.locate("Rate").first.text)
rate *= TROY_OUNCE_GRAMS if PRECIOUS_METALS.include?(iso)
rate / amount
end
end
end
end