class QontoOfx::Converter

Convert a JSON transactions listing into an OFX hash

Public Class Methods

new(slug, token) click to toggle source
# File lib/converter.rb, line 11
def initialize(slug, token)
  @gateway = ApiGateway.new slug, token
  @ofx_validator = OfxValidator.new
end

Public Instance Methods

add_bankacctfrom_block(xml, bank_account) click to toggle source
# File lib/converter.rb, line 69
def add_bankacctfrom_block(xml, bank_account)
  xml.BANKACCTFROM do
    xml.BANKID '0000'
    xml.ACCTID bank_account['iban'][-21..-1]
    xml.ACCTTYPE 'CHECKING'
  end
end
add_signonmsgsrsv1_block(xml) click to toggle source
# File lib/converter.rb, line 84
def add_signonmsgsrsv1_block(xml)
  xml.SIGNONMSGSRSV1 do
    xml.parent.namespace = nil
    xml.SONRS do
      add_status_block xml
      xml.DTSERVER Time.now.strftime('%Y%m%d%H%M%S')
      xml.LANGUAGE 'FRE'
    end
  end
end
add_status_block(xml, code = 0, severity = 'INFO') click to toggle source
# File lib/converter.rb, line 77
def add_status_block(xml, code = 0, severity = 'INFO')
  xml.STATUS do
    xml.CODE code
    xml.SEVERITY severity
  end
end
compute_dates_range(transaction, dtstart, dtend) click to toggle source
# File lib/converter.rb, line 95
def compute_dates_range(transaction, dtstart, dtend)
  unless transaction['settled_at'].nil?
    tmp_dtstart = Time.parse(transaction['emitted_at'])
    dtstart = tmp_dtstart if dtstart.nil? || tmp_dtstart < dtstart

    tmp_dtend = Time.parse(transaction['emitted_at'])
    dtend = tmp_dtend if dtend.nil? || tmp_dtend > dtend
  end
  [dtstart, dtend]

end
convert(remove_ns = false) click to toggle source

valid_ofx = false removes the namespaces

# File lib/converter.rb, line 17
def convert(remove_ns = false)
  organization = @gateway.fetch_organization['organization']

  builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8')
  builder[:ofx].OFX('xmlns:ofx' => 'http://ofx.net/types/2003/04') do |xml|
    add_signonmsgsrsv1_block xml

    xml.BANKMSGSRSV1 do
      xml.parent.namespace = nil
      organization['bank_accounts'].each do |bank_account|
        xml.STMTTRNRS do
          xml.TRNUID 1
          add_status_block xml

          xml.STMTRS do
            xml.CURDEF 'EUR'
            add_bankacctfrom_block xml, bank_account

            xml.BANKTRANLIST do
              process_transactions xml, bank_account
            end

            xml.LEDGERBAL do
              xml.BALAMT bank_account['balance']
              xml.DTASOF Time.now.strftime('%Y%m%d%H%M%S')
            end
          end
        end
      end
    end
  end

  move_to_first_position(builder, '//DTEND')
  move_to_first_position(builder, '//DTSTART')


  result = builder.to_xml
  raise 'generation failed (invalid OFX)' unless @ofx_validator.valid? result
  result = result.gsub(
    'ofx:OFX',
    'OFX'
  ).gsub(' xmlns:ofx="http://ofx.net/types/2003/04"', '') if remove_ns
  result
end
correct_value(transaction, key) click to toggle source
# File lib/converter.rb, line 139
def correct_value(transaction, key)
  if transaction['side'] === 'debit'
    -transaction[key]
  else
    transaction[key]
  end
end
move_to_first_position(builder, path) click to toggle source
# File lib/converter.rb, line 62
def move_to_first_position(builder, path)
  builder.doc.xpath(path).each do |el|
    el.parent.children.first.before(el)
  end

end
operation_type(transaction) click to toggle source
# File lib/converter.rb, line 147
def operation_type(transaction)
  case transaction['operation_type']
  when 'income'
    'XFER'
  when 'card'
      'POS'
  else
      transaction['side'].upcase
  end
end
process_transactions(xml, account) click to toggle source
# File lib/converter.rb, line 107
def process_transactions(xml, account)
  url = "https://thirdparty.qonto.eu/v2/transactions?slug=#{account['slug']}&iban=#{account['iban']}"

  dtstart = dtend = nil
  loop do
    response = @gateway.fetch_transactions url
    transactions = response['transactions']

    transactions.each do |transaction|
      dtstart, dtend = compute_dates_range transaction, dtstart, dtend
      next if transaction['settled_at'].nil?
      xml.STMTTRN do
        xml.TRNTYPE operation_type(transaction)
        xml.DTPOSTED Time.parse(
          transaction['settled_at']
        ).strftime('%Y%m%d%H%M%S')
        xml.TRNAMT correct_value(transaction, 'amount')
        xml.FITID transaction['transaction_id']
        xml.NAME transaction['label'][0..31]

        xml.MEMO transaction['note'] unless transaction['note'].nil? || transaction['note'].empty?
      end
    end

    url = response['meta']['next_page']
    break if url.nil?
  end
  xml.DTEND((dtend || Time.now).strftime('%Y%m%d%H%M%S'))
  xml.DTSTART((dtstart || Time.now).strftime('%Y%m%d%H%M%S'))
  nil
end