amex 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ settings.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'httparty', '0.9.0'
4
+ gem 'nokogiri', '1.5.6'
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ httparty (0.9.0)
5
+ multi_json (~> 1.0)
6
+ multi_xml
7
+ multi_json (1.5.0)
8
+ multi_xml (0.5.1)
9
+ nokogiri (1.5.6)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ httparty (= 0.9.0)
16
+ nokogiri (= 1.5.6)
@@ -0,0 +1,91 @@
1
+ ## Amex
2
+
3
+ Welcome to the last continuation of my Ruby-based assault on various online
4
+ banking systems, much like my
5
+ [Lloyds TSB screen scraper](https://github.com/timrogers/lloydstsb).
6
+
7
+ However, this one doesn't rely on nasty screen-scraping. Instead, it uses
8
+ the previous unknown internal API used by American Express for their
9
+ "Amex UK" iPhone app. I suspect it works elsewhere, but I haven't tested.
10
+
11
+ ### Changelog
12
+
13
+ __v0.1.0__ - Original version
14
+ __v0.2.0__ - Support for multiple American Express cards, parsing using
15
+ Nokogiri
16
+
17
+ ### Usage
18
+
19
+ The file `example.rb` provides a very simple example of how the code works, but here's a step by step:
20
+
21
+ 1. Ensure the gem is installed, and then include it in your Ruby file, or in your Gemfile where appropriate:
22
+
23
+ ```
24
+ $ gem install amex
25
+ `require 'amex'
26
+ ```
27
+
28
+ 2. You'll just need two variables, @username and @password, each unsurprisingly corresponding to different authentication details used
29
+
30
+ ```
31
+ @username = "chuck_norris"
32
+ @password = "roundhousekick123"
33
+ ```
34
+
35
+ 3. Instantiate a new instance of the `Amex::Client` object, passing in the
36
+ username and password - this is used to perform the authentication required.
37
+
38
+ `client = Amex::Client.new(@username, @password)`
39
+
40
+ 4. Call the `account` method of the object you just made - it'll take a few seconds, and will return an Amex::CardAccount object. There'll only be one, since this
41
+ only supports one card at a time right now.
42
+
43
+ ```
44
+ accounts = client.accounts
45
+ puts account.first.product
46
+ puts account.first.type
47
+ ```
48
+
49
+ ### Data models
50
+
51
+ An `Amex::CardAccount` is created by `Amex::CardAccount.new` passing in a hash
52
+ of the parsed XML. The parsing is done by `Amex::Client`.
53
+
54
+ An __Amex::CardAccount__ instance has the following attributes:
55
+
56
+ * __product (string)__ - the type of card (e.g. "The Preferred Rewards Gold Card®")
57
+ * __card_number_suffix (string)__ - the last five digits of your card number
58
+ * __lending_type (string)__ - either "Charge" or "Credit", depending on the type of credit arrangement you have
59
+ * __card_member_name (string)__ - your name, as recorded as the account holder
60
+ * __past_due (boolean)__ - is the card past its due payment date?
61
+ * __cancelled?__ (boolean)__ - has the account been cancelled?
62
+ * __is_basic/centurion/platinum/premium] (boolean)__ - which type of account does this conform to?
63
+ * __market (string)__ - the market that your card is registered too, e.g. "en_GB"
64
+ * __card__art (string)__ - a URL for an image of your card
65
+ * __loyalty_indicator (boolean)__ - does this card have some
66
+ kind of loyalty scheme active? (e.g. Membership Rewards)
67
+ * __loyalty_programmes (array of Amex::LoyaltyProgramme objects)__ - the loyalty programmes this card belongs to
68
+ * __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
69
+ * __statement_balance (float)__ - the amount of the last statement on your account
70
+ * __payment_credits (float)__ - the combination of current payments and credits on your account
71
+ * __recent_charges (float)__ - charges since your last statement was issued (I believe)
72
+ * __total_balance (float)__ - what American Express refer to as your total balance, whatever that is!
73
+ * __payment_due (float)__ - the amount of money you need to pay before `payment_due_date`
74
+ * __payment_due_date (DateTime)__ - when the `payment_due` needs to be paid by
75
+
76
+ There are lots of extra useful methods here to make accessing
77
+ some of the various properties easier. They're very self-explanatory - check `lib/amex/card_account.rb`.
78
+
79
+ A __LloydsTSB::LoyaltyProgramme has just two attributes:
80
+
81
+ * __name (string)__ - The name of the programme, most often "Membership Rewards"
82
+ * __balance (integer)__ - The balance of the programme
83
+
84
+ ### Limitations
85
+
86
+ * There's no support for viewing transactions yet - watch this space!
87
+
88
+ ### License
89
+
90
+ Use this for what you will, as long as it isn't evil. If you make any changes or cool improvements, please let me know at <tim+amex@tim-rogers.co.uk>.
91
+
Binary file
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../lib/amex/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'amex'
5
+ gem.version = Amex::VERSION.dup
6
+ gem.authors = ['Tim Rogers']
7
+ gem.email = ['tim@tim-rogers.co.uk']
8
+ gem.summary = 'A library for accessing data on an American Express account'
9
+ gem.homepage = 'https://github.com/timrogers/amex'
10
+
11
+ gem.add_runtime_dependency "httparty"
12
+ gem.add_runtime_dependency "nokogiri"
13
+
14
+ gem.files = `git ls-files`.split("\n")
15
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'amex'
3
+
4
+ # Bring in the settings.rb file - this isn't included in the repository,
5
+ # but it should just contain two class variables, `username` and `password`
6
+ require "#{File.dirname(__FILE__)}/settings.rb"
7
+
8
+ client = Amex::Client.new(@username, @password)
9
+ accounts = client.accounts
10
+ puts accounts.first.inspect
@@ -1,5 +1,6 @@
1
1
  require 'erb'
2
2
  require 'httparty'
3
+ require 'nokogiri'
3
4
 
4
5
  module Amex
5
6
  class Client
@@ -23,7 +24,7 @@ module Amex
23
24
  ERB.new(xml).result(binding)
24
25
  end
25
26
 
26
- def account
27
+ def accounts
27
28
  # This only supports one account for now, because I'm lazy and I
28
29
  # hate traversing XML...
29
30
  options = { :body => { "PayLoadText" => request_xml }}
@@ -31,30 +32,43 @@ module Amex
31
32
  '/myca/intl/moblclient/emea/ws.do?Face=en_GB', options
32
33
  )
33
34
 
34
- xml = MultiXml.parse(response)['XMLResponse']
35
+ xml = Nokogiri::XML(response.body)
36
+ xml = xml.css("XMLResponse")
35
37
 
36
- if xml['ServiceResponse']['Status'] != "success"
38
+ if xml.css('ServiceResponse Status').text != "success"
37
39
  raise "There was a problem logging in to American Express."
38
40
  else
39
- account_details = {}
40
- xml["CardAccounts"]["CardAccount"]["CardData"]["param"].each do |item|
41
- account_details[item['name']] = item['__content__']
42
- end
41
+ accounts = [] # We'll store all the accounts in here!
43
42
 
44
- xml["CardAccounts"]["CardAccount"]["AccountSummaryData"]["SummaryElement"].each do |item|
45
- account_details[item['name']] = item['value'] ? item['value'].to_f : item['formattedValue']
46
- end
43
+ xml.css('CardAccounts CardAccount').each do |item|
44
+ account_details = {} # All the attributes from the XML go in here
45
+ # For each of the CardAccount objects, let's first go through
46
+ # the CardData to pull out lots of nice information
47
+ item.css('CardData param').each do |attribute|
48
+ account_details[attribute.attr('name')] = attribute.text
49
+ end
47
50
 
48
- account = Amex::CardAccount.new(account_details)
51
+ # Now let's go through the AccountSummaryData to find all the
52
+ # various bits of balance information
53
+ item.css('AccountSummaryData SummaryElement').each do |attribute|
54
+ account_details[attribute.attr('name')] = attribute.attr('value') ? attribute.attr('value').to_f : attribute.attr('formattedValue')
55
+ end
56
+
57
+ # We have all the attributes ready to go, so let's make an
58
+ # Amex::CardAccount object
59
+ account = Amex::CardAccount.new(account_details)
49
60
 
50
- xml["CardAccounts"]["CardAccount"]["LoyaltyProgramData"].each do |item|
51
- item.each do |part|
52
- next if part.class == String
53
- account.loyalty_programmes << Amex::LoyaltyProgramme.new(part['label'], part['formattedValue'].gsub(",", "").to_i)
61
+ # Finally, let's rip out all the loyalty balances...
62
+ item.css('LoyaltyProgramData LoyaltyElement').each do |element|
63
+ account.loyalty_programmes << Amex::LoyaltyProgramme.new(
64
+ element.attr('label'), element.attr('formattedValue').gsub(",", "").to_i
65
+ )
54
66
  end
67
+ accounts << account
68
+
55
69
  end
56
70
 
57
- account
71
+ accounts
58
72
  end
59
73
 
60
74
  end
@@ -1,3 +1,3 @@
1
1
  module Amex
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
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.1.0
4
+ version: 0.2.0
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-26 00:00:00.000000000 Z
12
+ date: 2012-12-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: nokogiri
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  description:
31
47
  email:
32
48
  - tim@tim-rogers.co.uk
@@ -34,13 +50,21 @@ executables: []
34
50
  extensions: []
35
51
  extra_rdoc_files: []
36
52
  files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - README.md
57
+ - amex-0.1.0.gem
58
+ - amex-0.2.0.gem
59
+ - amex.gemspec
60
+ - example.rb
37
61
  - lib/amex.rb
38
62
  - lib/amex/card_account.rb
39
63
  - lib/amex/client.rb
64
+ - lib/amex/data/request.xml
40
65
  - lib/amex/loyalty_programme.rb
41
66
  - lib/amex/utils.rb
42
67
  - lib/amex/version.rb
43
- - lib/amex/data/request.xml
44
68
  homepage: https://github.com/timrogers/amex
45
69
  licenses: []
46
70
  post_install_message: