Class Bankjob::Transaction
In: lib/bankjob/transaction.rb
Parent: Object

A Transaction object represents a transaction in a bank account (a withdrawal, deposit, transfer, etc) and is generally the result of running a Bankjob scraper.

A Scraper will create Transactions while scraping web pages in an online banking site. These Transactions will be collected in a Statement object which will then be written to a file.

A Transaction object knows how to write itself as a record in a CSV (Comma Separated Values) file using to_csv or as an XML element in an OFX (Open Financial eXchange file using to_ofx



CREDIT = "CREDIT"   OFX transaction type for Generic credit
DEBIT = "DEBIT"   OFX transaction type for Generic debit
INT = "INT"   OFX transaction type for Interest earned or paid. (Depends on signage of amount)
DIV = "DIV"   OFX transaction type for Dividend
FEE = "FEE"   OFX transaction type for FI fee
SRVCHG = "SRVCHG"   OFX transaction type for Service charge
DEP = "DEP"   OFX transaction type for Deposit
ATM = "ATM"   OFX transaction type for ATM debit or credit. (Depends on signage of amount)
POS = "POS"   OFX transaction type for Point of sale debit or credit. (Depends on signage of amount)
XFER = "XFER"   OFX transaction type for Transfer
CHECK = "CHECK"   OFX transaction type for Check
PAYMENT = "PAYMENT"   OFX transaction type for Electronic payment
CASH = "CASH"   OFX transaction type for Cash withdrawal
DIRECTDEP = "DIRECTDEP"   OFX transaction type for Direct deposit
DIRECTDEBIT = "DIRECTDEBIT"   OFX transaction type for Merchant initiated debit
REPEATPMT = "REPEATPMT"   OFX transaction type for Repeating payment/standing order
OTHER = "OTHER"   OFX transaction type for Other


amount  [RW]  amount of the credit or debit (negative for debits) Translates to OFX element TRNAMT
check_number  [RW]  the cheque number of a cheque transaction This is of type Payee and translates to OFX element CHECKNUM
date  [RW]  date of the transaction Translates to OFX element DTPOSTED
description  [RW]  description of the transaction This description is typically set by taking the raw description and applying rules. If it is not set explicitly it returns the same value as raw_description Translates to OFX element MEMO
new_balance  [RW]  account balance after the transaction Not used in OFX but important for working out statement balances
ofx_id  [RW]  the generated unique id for this transaction in an OFX record Translates to OFX element FITID this is generated if not set
payee  [RW]  the payee of an expenditure (ie a debit or transfer) This is of type Payee and translates to complex OFX element PAYEE
raw_description  [RW]  the original format of the description as scraped from the bank site This allows the raw information to be preserved when modifying the description with transaction rules (see Scraper#transaction_rule) This does not appear in the OFX output, only description does.
real_amount  [R]  the numeric real-number amount of the transaction.

The transaction amount is typically a string and may hold commas for 1000s or for decimal separators, making it unusable for mathematical operations.

This attribute returns the amount converted to a Ruby Float, which can be used in operations like: <tt>

  if (transaction.real_amount < 0)
    puts "It's a debit!"

The real_amount attribute is calculated using the decimal separator passed into the constructor (defaults to ".") See Scraper#decimal

This attribute is not used in OFX.

real_new_balance  [R]  account balance after the transaction as a numeric Ruby Float Not used in OFX but important for working out statement balances in calculations (see real_amount)
type  [RW]  OFX type of the transaction (credit, debit, atm withdrawal, etc) Translates to the OFX element TRNTYPE and according to the OFX 2.0.3 schema this can be one of
  • INT
  • DIV
  • FEE
  • DEP
  • ATM
  • POS
  • XFER
  • CASH
value_date  [RW]  the date the value affects the account (e.g. funds become available) Translates to OFX element DTUSER

Public Class methods

Generates a string for use as a header in a CSV file for transactions. This will produce the following string:

date, value_date, description, real_amount, real_new_balance, amount, new_balance, raw_description, ofx_id


# File lib/bankjob/transaction.rb, line 259
    def self.csv_header
      %w{ Date Value-Date Description Amount New-Balance Raw-Amount Raw-New-Balance Raw-Description OFX-ID }.to_csv

Creates a new Transaction from a string that defines a row in a CSV file.

csv_row must hold an array of values in precisely this order:

date, value_date, description, real_amount, real_new_balance, amount, new_balance, raw_description, ofx_id

(The format should be the same as that produced by to_csv)


# File lib/bankjob/transaction.rb, line 272
    def self.from_csv(csv_row, decimal)
      if (csv_row.length != 9)  # must have 9 cols

        csv_lines = csv_row.join("\n\t")
        msg = "Failed to create Transaction from csv row: \n\t#{csv_lines}\n"
        msg << " - 9 columns are required in the form: date, value_date, "
        msg << "description, real_amount, real_new_balance, amount, new_balance, "
        msg << "raw_description, ofx_id"
        raise msg
      tx =, tx.value_date, tx.description = csv_row[0..2]
      # skip real_amount and real_new_balance, they're read only and calculated

      tx.amount, tx.new_balance, tx.raw_description, tx.ofx_id = csv_row[5..8]
      return tx

Creates a new Transaction with the specified attributes.


# File lib/bankjob/transaction.rb, line 166
    def initialize(decimal = ".")
      @ofx_id = nil
      @date = nil
      @value_date = nil
      @raw_description = nil
      @description = nil
      @amount = 0
      @new_balance = 0
      @decimal = decimal

      # Always create a Payee even if it doesn't get used - this ensures an empty

      # <PAYEE> element in the OFX output which is more correct and, for one thing,

      # stops Wesabe from adding UNKNOWN PAYEE to every transaction (even deposits)

      @payee =
      @check_number = nil
      @type = OTHER

Public Instance methods


# File lib/bankjob/transaction.rb, line 184
    def date=(raw_date_time)
      @date = Bankjob.create_date_time(raw_date_time)

Returns the description, defaulting to the raw_description if no specific description has been set by the user.


# File lib/bankjob/transaction.rb, line 215
    def description()
      @description.nil? ? raw_description : @description

Creates a unique ID for the transaction for use in OFX documents, unless one has already been set. All OFX transactions need a unique identifier.

Note that this is generated by creating an MD5 digest of the transaction date, raw description, type, amount and new_balance. Which means that two identical transactions will always produce the same ofx_id. (This is important so that repeated scrapes of the same transaction value

 produce identical ofx_id values)


# File lib/bankjob/transaction.rb, line 203
    def ofx_id() 
      if @ofx_id.nil?
        text = "#{@date}:#{@raw_description}:#{@type}:#{@amount}:#{@new_balance}"
        @ofx_id= Digest::MD5.hexdigest(text)
      return @ofx_id

Returns the Transaction amount attribute as a ruby Float after replacing the decimal separator with a . and stripping any other separators.


# File lib/bankjob/transaction.rb, line 224
    def real_amount()
      Bankjob.string_to_float(amount, @decimal)

Returns the new balance after the transaction as a ruby Float after replacing the decimal separator with a . and stripping any other separators.


# File lib/bankjob/transaction.rb, line 233
    def real_new_balance()
      Bankjob.string_to_float(new_balance, @decimal)

Generates a string representing this Transaction as comma separated values in the form:

date, value_date, description, real_amount, real_new_balance, amount, new_balance, raw_description, ofx_id


# File lib/bankjob/transaction.rb, line 243
    def to_csv
      # if there's a payee, prepend their name to the description - otherwise skip it

      if (not payee.nil? and (not
        desc = + " - " + description
        desc = description
      [Bankjob.date_time_to_csv(date), Bankjob.date_time_to_csv(value_date), desc, real_amount, real_new_balance, amount, new_balance, raw_description, ofx_id].to_csv

Generates an XML string adhering to the OFX standard (see Open Financial Exchange representing a single Transaction XML element.

The OFX 2 schema defines a STMTTRN (SatementTransaction) as follows:

 <xsd:complexType name="StatementTransaction">
       The OFX element "STMTTRN" is of type "StatementTransaction"
     <xsd:element name="TRNTYPE" type="ofx:TransactionEnum"/>
     <xsd:element name="DTPOSTED" type="ofx:DateTimeType"/>
     <xsd:element name="DTUSER" type="ofx:DateTimeType" minOccurs="0"/>
     <xsd:element name="DTAVAIL" type="ofx:DateTimeType" minOccurs="0"/>
     <xsd:element name="TRNAMT" type="ofx:AmountType"/>
     <xsd:element name="FITID" type="ofx:FinancialInstitutionTransactionIdType"/>
     <xsd:sequence minOccurs="0">
       <xsd:element name="CORRECTFITID" type="ofx:FinancialInstitutionTransactionIdType"/>
       <xsd:element name="CORRECTACTION" type="ofx:CorrectiveActionEnum"/>
     <xsd:element name="SRVRTID" type="ofx:ServerIdType" minOccurs="0"/>
     <xsd:element name="CHECKNUM" type="ofx:CheckNumberType" minOccurs="0"/>
     <xsd:element name="REFNUM" type="ofx:ReferenceNumberType" minOccurs="0"/>
     <xsd:element name="SIC" type="ofx:StandardIndustryCodeType" minOccurs="0"/>
     <xsd:element name="PAYEEID" type="ofx:PayeeIdType" minOccurs="0"/>
     <xsd:choice minOccurs="0">
       <xsd:element name="NAME" type="ofx:GenericNameType"/>
       <xsd:element name="PAYEE" type="ofx:Payee"/>
     <xsd:choice minOccurs="0">
       <xsd:element name="BANKACCTTO" type="ofx:BankAccount"/>
       <xsd:element name="CCACCTTO" type="ofx:CreditCardAccount"/>
     <xsd:element name="MEMO" type="ofx:MessageType" minOccurs="0"/>
     <xsd:choice minOccurs="0">
       <xsd:element name="CURRENCY" type="ofx:Currency"/>
       <xsd:element name="ORIGCURRENCY" type="ofx:Currency"/>
     <xsd:element name="INV401KSOURCE" type="ofx:Investment401kSourceEnum" minOccurs="0"/>


# File lib/bankjob/transaction.rb, line 334
    def to_ofx
      buf = ""
      # Set margin=5 to indent it nicely within the output from Statement.to_ofx

      x = => buf, :indent => 2, :margin=>5)
      x.STMTTRN {       # transaction statement

        x.TRNTYPE type
        x.DTPOSTED Bankjob.date_time_to_ofx(date)       #Date transaction was posted to account, [datetime] yyyymmdd or yyyymmddhhmmss

        x.TRNAMT amount #Ammount of transaction [amount] can be , or . separated

        x.FITID ofx_id
        x.CHECKNUM check_number unless check_number.nil?
        buf << payee.to_ofx unless payee.nil?
        #x.NAME description

        x.MEMO description
      return buf

Produces a string representation of the transaction


# File lib/bankjob/transaction.rb, line 354
    def to_s
      "#{self.class} - ofx_id: #{@ofx_id}, date:#{@date}, raw description: #{@raw_description}, type: #{@type} amount: #{@amount}, new balance: #{@new_balance}"


# File lib/bankjob/transaction.rb, line 188
    def value_date=(raw_date_time)
      @value_date = Bankjob.create_date_time(raw_date_time)