Class: Bankjob::Transaction
- Inherits:
-
Object
- Object
- Bankjob::Transaction
- Defined in:
- lib/bankjob/transaction.rb
Overview
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 www.ofx.net) file using to_ofx
Constant Summary collapse
- CREDIT =
OFX transaction type for Generic credit
"CREDIT"
- DEBIT =
OFX transaction type for Generic debit
"DEBIT"
- INT =
OFX transaction type for Interest earned or paid. (Depends on signage of amount)
"INT"
- DIV =
OFX transaction type for Dividend
"DIV"
- FEE =
OFX transaction type for FI fee
"FEE"
- SRVCHG =
OFX transaction type for Service charge
"SRVCHG"
- DEP =
OFX transaction type for Deposit
"DEP"
- ATM =
OFX transaction type for ATM debit or credit. (Depends on signage of amount)
"ATM"
- POS =
OFX transaction type for Point of sale debit or credit. (Depends on signage of amount)
"POS"
- XFER =
OFX transaction type for Transfer
"XFER"
- CHECK =
OFX transaction type for Check
"CHECK"
- PAYMENT =
OFX transaction type for Electronic payment
"PAYMENT"
- CASH =
OFX transaction type for Cash withdrawal
"CASH"
- DIRECTDEP =
OFX transaction type for Direct deposit
"DIRECTDEP"
- DIRECTDEBIT =
OFX transaction type for Merchant initiated debit
"DIRECTDEBIT"
- REPEATPMT =
OFX transaction type for Repeating payment/standing order
"REPEATPMT"
- OTHER =
OFX transaction type for Other
"OTHER"
Instance Attribute Summary collapse
-
#amount ⇒ Object
amount of the credit or debit (negative for debits) Translates to OFX element TRNAMT.
-
#check_number ⇒ Object
the cheque number of a cheque transaction This is of type Payee and translates to OFX element CHECKNUM.
-
#date ⇒ Object
date of the transaction Translates to OFX element DTPOSTED.
-
#description ⇒ Object
Returns the description, defaulting to the
raw_description
if no specific description has been set by the user. -
#new_balance ⇒ Object
account balance after the transaction Not used in OFX but important for working out statement balances.
-
#ofx_id ⇒ Object
Creates a unique ID for the transaction for use in OFX documents, unless one has already been set.
-
#payee ⇒ Object
the payee of an expenditure (ie a debit or transfer) This is of type Payee and translates to complex OFX element PAYEE.
-
#raw_description ⇒ Object
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, onlydescription
does. -
#real_amount ⇒ Object
readonly
Returns the Transaction amount attribute as a ruby Float after replacing the decimal separator with a .
-
#real_new_balance ⇒ Object
readonly
Returns the new balance after the transaction as a ruby Float after replacing the decimal separator with a .
-
#type ⇒ Object
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 * CREDIT * DEBIT * INT * DIV * FEE * SRVCHG * DEP * ATM * POS * XFER * CHECK * PAYMENT * CASH * DIRECTDEP * DIRECTDEBIT * REPEATPMT * OTHER.
-
#value_date ⇒ Object
the date the value affects the account (e.g. funds become available) Translates to OFX element DTUSER.
Class Method Summary collapse
-
.csv_header ⇒ Object
Generates a string for use as a header in a CSV file for transactions.
-
.from_csv(csv_row, decimal) ⇒ Object
Creates a new Transaction from a string that defines a row in a CSV file.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Overrides == to allow comparison of Transaction objects so that they can be merged in Statements.
-
#eql?(other) ⇒ Boolean
Overrides eql? so that array union will work when merging statements.
-
#hash ⇒ Object
Overrides hash so that array union will work when merging statements.
-
#initialize(decimal = ".") ⇒ Transaction
constructor
Creates a new Transaction with the specified attributes.
-
#to_csv ⇒ Object
Generates a string representing this Transaction as comma separated values in the form:.
-
#to_ofx ⇒ Object
Generates an XML string adhering to the OFX standard (see Open Financial Exchange www.ofx.net) representing a single Transaction XML element.
-
#to_s ⇒ Object
Produces a string representation of the transaction.
Constructor Details
#initialize(decimal = ".") ⇒ Transaction
Creates a new Transaction with the specified attributes.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# 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 = Payee.new() @check_number = nil @type = OTHER end |
Instance Attribute Details
#amount ⇒ Object
amount of the credit or debit (negative for debits) Translates to OFX element TRNAMT
118 119 120 |
# File 'lib/bankjob/transaction.rb', line 118 def amount @amount end |
#check_number ⇒ Object
the cheque number of a cheque transaction This is of type Payee and translates to OFX element CHECKNUM
139 140 141 |
# File 'lib/bankjob/transaction.rb', line 139 def check_number @check_number end |
#date ⇒ Object
date of the transaction Translates to OFX element DTPOSTED
97 98 99 |
# File 'lib/bankjob/transaction.rb', line 97 def date @date end |
#description ⇒ Object
Returns the description, defaulting to the raw_description
if no specific description has been set by the user.
108 109 110 |
# File 'lib/bankjob/transaction.rb', line 108 def description @description end |
#new_balance ⇒ Object
account balance after the transaction Not used in OFX but important for working out statement balances
122 123 124 |
# File 'lib/bankjob/transaction.rb', line 122 def new_balance @new_balance end |
#ofx_id ⇒ Object
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)
131 132 133 |
# File 'lib/bankjob/transaction.rb', line 131 def ofx_id @ofx_id end |
#payee ⇒ Object
the payee of an expenditure (ie a debit or transfer) This is of type Payee and translates to complex OFX element PAYEE
135 136 137 |
# File 'lib/bankjob/transaction.rb', line 135 def payee @payee end |
#raw_description ⇒ Object
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.
114 115 116 |
# File 'lib/bankjob/transaction.rb', line 114 def raw_description @raw_description end |
#real_amount ⇒ Object (readonly)
Returns the Transaction amount attribute as a ruby Float after replacing the decimal separator with a . and stripping any other separators.
161 162 163 |
# File 'lib/bankjob/transaction.rb', line 161 def real_amount @real_amount end |
#real_new_balance ⇒ Object (readonly)
Returns the new balance after the transaction as a ruby Float after replacing the decimal separator with a . and stripping any other separators.
127 128 129 |
# File 'lib/bankjob/transaction.rb', line 127 def real_new_balance @real_new_balance end |
#type ⇒ Object
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
-
CREDIT
-
DEBIT
-
INT
-
DIV
-
FEE
-
SRVCHG
-
DEP
-
ATM
-
POS
-
XFER
-
CHECK
-
PAYMENT
-
CASH
-
DIRECTDEP
-
DIRECTDEBIT
-
REPEATPMT
-
OTHER
93 94 95 |
# File 'lib/bankjob/transaction.rb', line 93 def type @type end |
#value_date ⇒ Object
the date the value affects the account (e.g. funds become available) Translates to OFX element DTUSER
101 102 103 |
# File 'lib/bankjob/transaction.rb', line 101 def value_date @value_date end |
Class Method Details
.csv_header ⇒ Object
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
259 260 261 |
# 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 end |
.from_csv(csv_row, decimal) ⇒ Object
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
)
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# 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 end tx = Transaction.new(decimal) tx.date, 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 end |
Instance Method Details
#==(other) ⇒ Object
Overrides == to allow comparison of Transaction objects so that they can be merged in Statements. See Statement#merge
362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/bankjob/transaction.rb', line 362 def ==(other) #:nodoc: if other.kind_of?(Transaction) # sometimes the same date, when written and read back will not appear equal so convert to # a canonical string first return (Bankjob.date_time_to_ofx(@date) == Bankjob.date_time_to_ofx(other.date) and # ignore value date - it may be updated between statements # (consider using ofx_id here later) @raw_description == other.raw_description and @amount == other.amount and @type == other.type and @new_balance == other.new_balance) end end |
#eql?(other) ⇒ Boolean
Overrides eql? so that array union will work when merging statements
379 380 381 |
# File 'lib/bankjob/transaction.rb', line 379 def eql?(other) #:nodoc: return self == other end |
#hash ⇒ Object
Overrides hash so that array union will work when merging statements
386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/bankjob/transaction.rb', line 386 def hash() #:nodoc: prime = 31; result = 1; result = prime * result + @amount.to_i result = prime * result + @new_balance.to_i result = prime * result + (@date.nil? ? 0 : Bankjob.date_time_to_ofx(@date).hash); result = prime * result + (@raw_description.nil? ? 0 : @raw_description.hash); result = prime * result + (@type.nil? ? 0 : @type.hash); # don't use value date return result; end |
#to_csv ⇒ Object
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
243 244 245 246 247 248 249 250 251 |
# 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 payee.name.nil?)) desc = payee.name + " - " + description else desc = description end [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 end |
#to_ofx ⇒ Object
Generates an XML string adhering to the OFX standard (see Open Financial Exchange www.ofx.net) representing a single Transaction XML element.
The OFX 2 schema defines a STMTTRN (SatementTransaction) as follows:
<xsd:complexType name="StatementTransaction">
<xsd:annotation>
<xsd:documentation>
The OFX element "STMTTRN" is of type "StatementTransaction"
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<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:sequence>
<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>
<xsd:choice minOccurs="0">
<xsd:element name="BANKACCTTO" type="ofx:BankAccount"/>
<xsd:element name="CCACCTTO" type="ofx:CreditCardAccount"/>
</xsd:choice>
<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:choice>
<xsd:element name="INV401KSOURCE" type="ofx:Investment401kSourceEnum" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# 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 = Builder::XmlMarkup.new(:target => 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 end |
#to_s ⇒ Object
Produces a string representation of the transaction
354 355 356 |
# 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}" end |