amex 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/README.md +11 -81
- data/lib/amex/card_account.rb +72 -8
- data/lib/amex/client.rb +31 -11
- data/lib/amex/loyalty_programme.rb +8 -0
- data/lib/amex/transaction.rb +13 -0
- data/lib/amex/utils.rb +7 -7
- data/lib/amex/version.rb +1 -1
- metadata +3 -7
- data/amex-0.1.0.gem +0 -0
- data/amex-0.2.0.gem +0 -0
- data/amex-0.3.0.gem +0 -0
- data/amex-0.3.1.gem +0 -0
- data/amex-0.3.2.gem +0 -0
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
## Changelog
|
2
|
+
|
3
|
+
__v0.1.0__ - Original version
|
4
|
+
|
5
|
+
__v0.2.0__ - Support for multiple American Express cards, parsing using
|
6
|
+
Nokogiri
|
7
|
+
|
8
|
+
__v0.3.0__ - Adds support for loading the transactions from the most recent statement
|
9
|
+
(but it's broken because I forgot to change something from testing :( )
|
10
|
+
|
11
|
+
__v0.3.1__ - Working version of v0.3.0 that will successfully load transactions
|
12
|
+
from the most recent statement
|
13
|
+
|
14
|
+
__v0.3.2__ - Generates a fake HardwareId in the first request, since I'm
|
15
|
+
paranoid about American Express blocking 'dummy_device_id'
|
16
|
+
|
17
|
+
__v0.4.0__ - Improves transactions - adds support for lazy-loading and
|
18
|
+
pagination from Amex::CardAccount#transactions
|
19
|
+
|
20
|
+
__v0.4.1__ - Adds YARD documentation
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
amex (0.4.
|
4
|
+
amex (0.4.1)
|
5
5
|
httparty
|
6
6
|
nokogiri
|
7
7
|
httparty (0.9.0)
|
@@ -15,6 +15,6 @@ PLATFORMS
|
|
15
15
|
ruby
|
16
16
|
|
17
17
|
DEPENDENCIES
|
18
|
-
amex (= 0.4.
|
18
|
+
amex (= 0.4.1)
|
19
19
|
httparty (= 0.9.0)
|
20
20
|
nokogiri (= 1.5.6)
|
data/README.md
CHANGED
@@ -9,26 +9,9 @@ the previous unknown internal API used by American Express for their
|
|
9
9
|
"Amex UK" iPhone app. I suspect it works elsewhere, but I haven't tested.
|
10
10
|
|
11
11
|
This allows you to fetch the details of all the cards on your American
|
12
|
-
Express login, as well as
|
12
|
+
Express login, as well as transactions on each card.
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
__v0.1.0__ - Original version
|
17
|
-
|
18
|
-
__v0.2.0__ - Support for multiple American Express cards, parsing using
|
19
|
-
Nokogiri
|
20
|
-
|
21
|
-
__v0.3.0__ - Adds support for loading the transactions from the most recent statement
|
22
|
-
(but it's broken because I forgot to change something from testing :( )
|
23
|
-
|
24
|
-
__v0.3.1__ - Working version of v0.3.0 that will successfully load transactions
|
25
|
-
from the most recent statement
|
26
|
-
|
27
|
-
__v0.3.2__ - Generates a fake HardwareId in the first request, since I'm
|
28
|
-
paranoid about American Express blocking 'dummy_device_id'
|
29
|
-
|
30
|
-
__v0.4.0__ - Improves transactions - adds support for lazy-loading and
|
31
|
-
pagination from Amex::CardAccount#transactions
|
14
|
+
*See CHANGELOG.md for a changelog.*
|
32
15
|
|
33
16
|
|
34
17
|
### Usage
|
@@ -67,68 +50,15 @@ puts my_account.type
|
|
67
50
|
puts my_account.transactions.inspect
|
68
51
|
```
|
69
52
|
|
70
|
-
###
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
* __card_index (integer)__ - the internal number of the card on your account
|
80
|
-
in the Amex system, starting from 0 *(used internally by the gem)*
|
81
|
-
* __lending_type (string)__ - either "Charge" or "Credit", depending on the type of credit arrangement you have
|
82
|
-
* __card_member_name (string)__ - your name, as recorded as the account holder
|
83
|
-
* __past_due (boolean)__ - is the card past its due payment date?
|
84
|
-
* __cancelled?__ (boolean)__ - has the account been cancelled?
|
85
|
-
* __is_basic/centurion/platinum/premium] (boolean)__ - which type of account does this conform to?
|
86
|
-
* __market (string)__ - the market that your card is registered too, e.g. "en_GB"
|
87
|
-
* __card__art (string)__ - a URL for an image of your card
|
88
|
-
* __loyalty_indicator (boolean)__ - does this card have some
|
89
|
-
kind of loyalty scheme active? (e.g. Membership Rewards)
|
90
|
-
* __loyalty_programmes (array of Amex::LoyaltyProgramme objects)__ - the loyalty programmes this card belongs to
|
91
|
-
* __loyalty_balances (hash)__ - the loyalty balances on this card - the key is the name of the programme (string), and the balance is the value, as an integer
|
92
|
-
* __statement_balance (float)__ - the amount of the last statement on your account
|
93
|
-
* __payment_credits (float)__ - the combination of current payments and credits on your account
|
94
|
-
* __recent_charges (float)__ - charges since your last statement was issued (I believe)
|
95
|
-
* __total_balance (float)__ - what American Express refer to as your total balance, whatever that is!
|
96
|
-
* __payment_due (float)__ - the amount of money you need to pay before `payment_due_date`
|
97
|
-
* __payment_due_date (DateTime)__ - when the `payment_due` needs to be paid by
|
98
|
-
|
99
|
-
The transactions for a given account can be found by calling the `transaction`
|
100
|
-
method on a CardAccount. This takes a parameter, `billing_period`, which can
|
101
|
-
be an integer referring to a particular statement, or a range of integers.
|
102
|
-
|
103
|
-
To get transactions since the most recent statement, simply call
|
104
|
-
`account.transactions(0)` or `account.transactions`, since this is the default.
|
105
|
-
|
106
|
-
To get the last statement, call `account.transactions(1)`. To get from now up
|
107
|
-
to 5 statements ago, call `account.transactions(0..5)`. You get the idea.
|
108
|
-
|
109
|
-
There are lots of extra useful methods here to make accessing
|
110
|
-
some of the various properties easier. They're very self-explanatory - check `lib/amex/card_account.rb`.
|
111
|
-
|
112
|
-
A __Amex::LoyaltyProgramme has just two attributes:
|
113
|
-
|
114
|
-
* __name (string)__ - The name of the programme, most often "Membership Rewards"
|
115
|
-
* __balance (integer)__ - The balance of the programme
|
116
|
-
|
117
|
-
An __Amex::Transaction represents a transaction in your most recent American
|
118
|
-
Express statement. It has four attributes:
|
119
|
-
|
120
|
-
* __amount (float)__ - The amount of the transaction
|
121
|
-
* __date (Date)__ - The date that the transaction was recorded
|
122
|
-
* __narrative (string)__ - The description shown on your statement, usually
|
123
|
-
contaning the name of the merchant and their location
|
124
|
-
* __extra_details (hash)__ - This hash contains any extra pieces of information
|
125
|
-
provided by American Express...for instance, foreign transactions have their
|
126
|
-
exchange rate and commission. The name of the attribute will be the key, and
|
127
|
-
its formatted value in the value in the hash.
|
128
|
-
|
129
|
-
There's one helper method currently available here, `is_foreign_transaction?`,
|
130
|
-
which returns a boolean representing whether the transaction was foreign (i.e.
|
131
|
-
in a non-native currency).
|
53
|
+
### Documentation
|
54
|
+
|
55
|
+
You can view the full YARD documentation [here](http://rubydoc.info/github/timrogers/amex/master/frames).
|
56
|
+
|
57
|
+
### Examples
|
58
|
+
|
59
|
+
* __[amex_alerts](https://github.com/timrogers/amex-alerts)__, a script
|
60
|
+
designed to be run as a cron which tracks and alerts you on your rewards
|
61
|
+
balances
|
132
62
|
|
133
63
|
### License
|
134
64
|
|
data/lib/amex/card_account.rb
CHANGED
@@ -7,6 +7,13 @@ module Amex
|
|
7
7
|
:total_balance, :payment_due, :payment_due_date, :loyalty_programmes,
|
8
8
|
:client
|
9
9
|
|
10
|
+
# Generates a CardAccount object from XML properties grabbed by the client
|
11
|
+
#
|
12
|
+
# @param [Hash] options A Hash containing XML properties pulled directly
|
13
|
+
# from the API XML
|
14
|
+
# @return [Amex::CardAccount] an object representing an American Express
|
15
|
+
# card
|
16
|
+
#
|
10
17
|
def initialize(options)
|
11
18
|
options.each do |key, value|
|
12
19
|
method = key.to_s.underscore + "="
|
@@ -15,15 +22,20 @@ module Amex
|
|
15
22
|
@loyalty_programmes = []
|
16
23
|
end
|
17
24
|
|
25
|
+
# Fetches transactions on an American Express card
|
26
|
+
#
|
27
|
+
# @param [Fixnum, Range] billing_period The billing period(s) to fetch
|
28
|
+
# transactions for, as either a single billing period (e.g. 0 or 1) or
|
29
|
+
# a range of periods to fetch (e.g. 0..3)
|
30
|
+
# @return [Array<Amex::Transaction>] an array of `Amex::Transaction` objects
|
31
|
+
# @note This can fetch either a single billing period or a range
|
32
|
+
# of billing periods, e.g:
|
33
|
+
# => account.transaction(0)
|
34
|
+
# fetches transactions since the last statement (default)
|
35
|
+
# => account.transaction(0..5)
|
36
|
+
# fetches transactions between now and five statements ago
|
37
|
+
#
|
18
38
|
def transactions(billing_period=0)
|
19
|
-
# Fetch the transactions for this account based upon the passed in
|
20
|
-
# options - this can fetch either a single billing period or a range
|
21
|
-
# of billing periods, e.g:
|
22
|
-
#
|
23
|
-
# => account.transaction(0) fetches transactions since the last statement
|
24
|
-
# (default)
|
25
|
-
# => account.transaction(0..5) fetches transactions between now and
|
26
|
-
# five statements ago
|
27
39
|
result = []
|
28
40
|
|
29
41
|
# Build an array of billing periods we need to fetch - this is almost
|
@@ -55,23 +67,46 @@ module Amex
|
|
55
67
|
result
|
56
68
|
end
|
57
69
|
|
70
|
+
# Returns the balance of the most recent statement
|
71
|
+
#
|
72
|
+
# @return [Float] the balance of the most recent statement
|
73
|
+
#
|
58
74
|
def statement_balance
|
59
75
|
@stmt_balance
|
60
76
|
end
|
61
77
|
|
78
|
+
# Returns the name of the card product that your card conforms to (e.g.
|
79
|
+
# "American Express Preferred Rewards Gold")
|
80
|
+
#
|
81
|
+
# @return [String] the name of the card product that your card conforms to
|
82
|
+
#
|
62
83
|
def product
|
63
84
|
@card_product
|
64
85
|
end
|
65
86
|
|
87
|
+
# Returns whether the card account is cancelled
|
88
|
+
#
|
89
|
+
# @return [Boolean] the cancellation status of this card, either true or
|
90
|
+
# false
|
66
91
|
def cancelled?
|
67
92
|
@cancelled
|
68
93
|
end
|
69
94
|
|
95
|
+
# Returns the date that the next payment on the card is due
|
96
|
+
#
|
97
|
+
# @return [DateTime] the date when the next payment against this account
|
98
|
+
# is due
|
70
99
|
def payment_due_date
|
71
100
|
# Overrides attr_accessor so it actually returns a DateTime, not String
|
72
101
|
DateTime.parse(@payment_due_date)
|
73
102
|
end
|
74
103
|
|
104
|
+
# Returns the type of account this card conforms to (generally not useful,
|
105
|
+
# probably largely used internally by American Express
|
106
|
+
#
|
107
|
+
# @return [:basic, :platinum, :centurion, :premium, :unknown] a symbol
|
108
|
+
# representing the 'type' of your card
|
109
|
+
#
|
75
110
|
def type
|
76
111
|
return :basic if @is_basic
|
77
112
|
return :platinum if @is_platinum
|
@@ -80,30 +115,59 @@ module Amex
|
|
80
115
|
:unknown
|
81
116
|
end
|
82
117
|
|
118
|
+
# Returns whether this account is a credit card
|
119
|
+
#
|
120
|
+
# @return [Boolean] true if the account is a credit card, false otherwise
|
121
|
+
#
|
83
122
|
def is_credit_card?
|
84
123
|
return true if @lending_type == "Credit"
|
85
124
|
false
|
86
125
|
end
|
87
126
|
|
127
|
+
# Returns whether this account is a charge card
|
128
|
+
#
|
129
|
+
# @return [Boolean] true if the account is a charge card, false otherwise
|
130
|
+
#
|
88
131
|
def is_charge_card?
|
89
132
|
return true if @lending_type == "Charge"
|
90
133
|
false
|
91
134
|
end
|
92
135
|
|
136
|
+
# Returns whether payment on this account is overdue
|
137
|
+
#
|
138
|
+
# @return [Boolean] true if the account is overdue, false otherwise
|
139
|
+
#
|
93
140
|
def overdue?
|
94
141
|
return true if @past_due
|
95
142
|
false
|
96
143
|
end
|
97
144
|
|
145
|
+
# Returns whether this account has a due payment (i.e. whether you need
|
146
|
+
# to pay American Express anything) (see #overdue?)
|
147
|
+
#
|
148
|
+
# @return [Boolean] true if the account has a due payment, false otherwise
|
149
|
+
#
|
98
150
|
def due?
|
99
151
|
return true if @payment_due.to_f > 0
|
100
152
|
false
|
101
153
|
end
|
102
154
|
|
155
|
+
# Returns whether this account has any kind of loyalty scheme attached
|
156
|
+
#
|
157
|
+
# @return [Boolean] true if the account has a loyalty scheme, false
|
158
|
+
# otherwise
|
159
|
+
#
|
103
160
|
def loyalty_enabled?
|
104
161
|
@loyalty_indicator
|
105
162
|
end
|
106
163
|
|
164
|
+
|
165
|
+
# Returns a hash of loyalty scheme balances for this account
|
166
|
+
#
|
167
|
+
# @return [Hash{String => String}] the loyalty balances for this account,
|
168
|
+
# with the key being the name of the loyalty scheme, and the value its
|
169
|
+
# balance
|
170
|
+
#
|
107
171
|
def loyalty_balances
|
108
172
|
result = {}
|
109
173
|
@loyalty_programmes.each do |programme|
|
data/lib/amex/client.rb
CHANGED
@@ -8,14 +8,23 @@ module Amex
|
|
8
8
|
include HTTParty
|
9
9
|
base_uri 'https://global.americanexpress.com/'
|
10
10
|
|
11
|
+
# Generates an Amex::Client object from a username and password
|
12
|
+
#
|
13
|
+
# @param [String] username Your American Express online services username
|
14
|
+
# @param [String] password Your American Express online services password
|
15
|
+
# @return [Amex::Client] an object representing an American Express online
|
16
|
+
# account
|
17
|
+
#
|
11
18
|
def initialize(username, password)
|
12
19
|
@username = username
|
13
20
|
@password = password
|
14
21
|
end
|
15
22
|
|
23
|
+
# Fetches the cards on an American Express online services account
|
24
|
+
#
|
25
|
+
# @return [Array<Amex::CardAccount>] an array of `Amex::CardAccount` objects
|
26
|
+
#
|
16
27
|
def accounts
|
17
|
-
# This only supports one account for now, because I'm lazy and I
|
18
|
-
# hate traversing XML...
|
19
28
|
options = { :body => { "PayLoadText" => request_xml }}
|
20
29
|
response = self.class.post(
|
21
30
|
'/myca/intl/moblclient/emea/ws.do?Face=en_GB', options
|
@@ -80,10 +89,17 @@ module Amex
|
|
80
89
|
|
81
90
|
end
|
82
91
|
|
92
|
+
# Generates the XML to send in a request to fetch transactions for a card
|
93
|
+
#
|
94
|
+
# @param [Integer] card_index The index of the card you're looking up
|
95
|
+
# in your account (see Amex::CardAccount#card_index)
|
96
|
+
# @param [Integer] billing_period The billing period to look at, with "0"
|
97
|
+
# being transactions since your last statement, "1" being your last
|
98
|
+
# statement, "2" the statement before that and so on....
|
99
|
+
#
|
100
|
+
# @return [String] XML to be sent in the request
|
101
|
+
#
|
83
102
|
def statement_request_xml(card_index, billing_period=0)
|
84
|
-
# Generates XML for grabbing the last statement's transactions for a
|
85
|
-
# card, using the card_index attribute from an account's XML
|
86
|
-
|
87
103
|
xml = File.read(
|
88
104
|
File.expand_path(File.dirname(__FILE__) + '/data/statement_request.xml')
|
89
105
|
)
|
@@ -95,10 +111,11 @@ module Amex
|
|
95
111
|
|
96
112
|
private
|
97
113
|
|
114
|
+
# Generates the XML to send in a request to fetch cards for an account
|
115
|
+
#
|
116
|
+
# @return [String] XML to be sent in the request
|
117
|
+
#
|
98
118
|
def request_xml
|
99
|
-
# Generates XML for the first request for account information, taking
|
100
|
-
# an XML template and interpolating some parts with ERB
|
101
|
-
|
102
119
|
xml = File.read(
|
103
120
|
File.expand_path(File.dirname(__FILE__) + '/data/request.xml')
|
104
121
|
)
|
@@ -110,10 +127,13 @@ module Amex
|
|
110
127
|
ERB.new(xml).result(binding)
|
111
128
|
end
|
112
129
|
|
130
|
+
# Generates a fake HardwareId to be sent in requests, in an attempt to
|
131
|
+
# hide what requests to the API are coming from this gem
|
132
|
+
#
|
133
|
+
# @return [String] a 40 character alphanumeric lower-case string, which
|
134
|
+
# is passed in with the original API request
|
135
|
+
#
|
113
136
|
def hardware_id
|
114
|
-
# Generates a fake HardwareId - a 40 character alphanumeric lower-case
|
115
|
-
# string, which is passed in with the original API request
|
116
|
-
|
117
137
|
chars = 'abcdefghjkmnpqrstuvwxyz1234567890'
|
118
138
|
id = ''
|
119
139
|
40.times { id << chars[rand(chars.size)] }
|
@@ -2,6 +2,14 @@ module Amex
|
|
2
2
|
class LoyaltyProgramme
|
3
3
|
attr_accessor :name, :balance
|
4
4
|
|
5
|
+
# Generates an Amex::LoyaltyProgramme object from a programme name and
|
6
|
+
# balance, grabbed from the XML
|
7
|
+
#
|
8
|
+
# @param [String] name The name of the reward programme
|
9
|
+
# @param [Fixnum] balance The balance of the reward programme
|
10
|
+
# @return [Amex::LoyaltyProgramme] an object representing a loyalty
|
11
|
+
# programme
|
12
|
+
#
|
5
13
|
def initialize(name, balance)
|
6
14
|
@name = name
|
7
15
|
@balance = balance
|
data/lib/amex/transaction.rb
CHANGED
@@ -4,6 +4,14 @@ module Amex
|
|
4
4
|
class Transaction
|
5
5
|
attr_reader :date, :narrative, :amount, :extra_details
|
6
6
|
|
7
|
+
# Generates an Amex::LoyaltyProgramme object from a Nokogiri object
|
8
|
+
# representing <Transaction> element
|
9
|
+
#
|
10
|
+
# @param [Nokogiri::XML::Element] transaction A <Transaction> node taken
|
11
|
+
# the API XML request, parsed by Nokogiri
|
12
|
+
# @return [Amex::Transaction] an object representing an individual
|
13
|
+
# transaction
|
14
|
+
#
|
7
15
|
def initialize(transaction)
|
8
16
|
# Pass this a <Transaction> element, and it'll parse it
|
9
17
|
@date = Date.strptime(transaction.css('TransChargeDate').text, '%m/%d/%y')
|
@@ -16,6 +24,11 @@ module Amex
|
|
16
24
|
end
|
17
25
|
end
|
18
26
|
|
27
|
+
# Returns whether the transaction was made abroad/in a foreign currency
|
28
|
+
#
|
29
|
+
# @return [Boolean] true if the transaction was made abroad/in a foreign
|
30
|
+
# currency, false otherwise
|
31
|
+
#
|
19
32
|
def is_foreign_transaction?
|
20
33
|
return true if @extra_details.has_key?('currencyRate')
|
21
34
|
false
|
data/lib/amex/utils.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
class String
|
2
|
+
|
3
|
+
# Converts a String object into a simple as used on an Amex::CardAccount
|
4
|
+
# object - the XML uses camelCase attributes, we want underscored ones
|
5
|
+
# which we can convert to symbol (e.g. cardProduct to card_product)
|
6
|
+
#
|
7
|
+
# @return [String] the reformatted string
|
8
|
+
#
|
2
9
|
def underscore
|
3
10
|
self.gsub(/::/, '/').
|
4
11
|
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
@@ -6,11 +13,4 @@ class String
|
|
6
13
|
tr("-", "_").
|
7
14
|
downcase
|
8
15
|
end
|
9
|
-
|
10
|
-
def to_bool
|
11
|
-
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
12
|
-
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
|
13
|
-
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
14
|
-
end
|
15
|
-
|
16
16
|
end
|
data/lib/amex/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httparty
|
@@ -51,14 +51,10 @@ extensions: []
|
|
51
51
|
extra_rdoc_files: []
|
52
52
|
files:
|
53
53
|
- .gitignore
|
54
|
+
- CHANGELOG.md
|
54
55
|
- Gemfile
|
55
56
|
- Gemfile.lock
|
56
57
|
- README.md
|
57
|
-
- amex-0.1.0.gem
|
58
|
-
- amex-0.2.0.gem
|
59
|
-
- amex-0.3.0.gem
|
60
|
-
- amex-0.3.1.gem
|
61
|
-
- amex-0.3.2.gem
|
62
58
|
- amex.gemspec
|
63
59
|
- example.rb
|
64
60
|
- lib/amex.rb
|
data/amex-0.1.0.gem
DELETED
Binary file
|
data/amex-0.2.0.gem
DELETED
Binary file
|
data/amex-0.3.0.gem
DELETED
Binary file
|
data/amex-0.3.1.gem
DELETED
Binary file
|
data/amex-0.3.2.gem
DELETED
Binary file
|