vault-invoice-builder-client 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.yardopts +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +56 -0
- data/README.md +67 -0
- data/Rakefile +11 -0
- data/lib/vault-invoice-builder-client.rb +17 -0
- data/lib/vault-invoice-builder-client/client.rb +67 -0
- data/lib/vault-invoice-builder-client/version.rb +8 -0
- data/test/client_test.rb +132 -0
- data/test/helper.rb +4 -0
- data/test/version_test.rb +9 -0
- data/vault-invoice-builder-client.gemspec +21 -0
- metadata +101 -0
data/.gitignore
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-m markdown
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/heroku/vault-test-tools.git
|
3
|
+
revision: 5eabd67610f279b81cadb803cee8ef704093a05d
|
4
|
+
specs:
|
5
|
+
vault-test-tools (0.2.2)
|
6
|
+
minitest
|
7
|
+
nokogiri
|
8
|
+
rack-perftools_profiler
|
9
|
+
rack-test
|
10
|
+
rdoc
|
11
|
+
redcarpet
|
12
|
+
turn
|
13
|
+
yard
|
14
|
+
|
15
|
+
PATH
|
16
|
+
remote: .
|
17
|
+
specs:
|
18
|
+
vault-invoice-builder-client (0.0.2)
|
19
|
+
excon
|
20
|
+
yajl-ruby
|
21
|
+
|
22
|
+
GEM
|
23
|
+
remote: http://rubygems.org/
|
24
|
+
specs:
|
25
|
+
ansi (1.4.3)
|
26
|
+
excon (0.16.10)
|
27
|
+
json (1.7.7)
|
28
|
+
minitest (4.6.0)
|
29
|
+
nokogiri (1.5.6)
|
30
|
+
open4 (1.3.0)
|
31
|
+
perftools.rb (2.0.0)
|
32
|
+
rack (1.5.2)
|
33
|
+
rack-perftools_profiler (0.6.0)
|
34
|
+
open4 (~> 1.0)
|
35
|
+
perftools.rb (~> 2.0.0)
|
36
|
+
rack (~> 1.0)
|
37
|
+
rack-test (0.6.2)
|
38
|
+
rack (>= 1.0)
|
39
|
+
rake (10.0.3)
|
40
|
+
rdoc (3.12.1)
|
41
|
+
json (~> 1.4)
|
42
|
+
redcarpet (2.2.2)
|
43
|
+
rr (1.0.4)
|
44
|
+
turn (0.9.6)
|
45
|
+
ansi
|
46
|
+
yajl-ruby (1.1.0)
|
47
|
+
yard (0.8.4.1)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
rake
|
54
|
+
rr
|
55
|
+
vault-invoice-builder-client!
|
56
|
+
vault-test-tools (~> 0.2.2)!
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Vault::InvoiceBuilder::Client
|
2
|
+
|
3
|
+
A Ruby client for the `Vault::InvoiceBuilder` HTTP API.
|
4
|
+
|
5
|
+
## Setting up a development environment
|
6
|
+
|
7
|
+
Install dependencies and run the test suite:
|
8
|
+
|
9
|
+
bundle install --binstubs vendor/bin
|
10
|
+
rbenv rehash
|
11
|
+
rake
|
12
|
+
|
13
|
+
Run tests:
|
14
|
+
|
15
|
+
rake test
|
16
|
+
|
17
|
+
See tasks:
|
18
|
+
|
19
|
+
rake -T
|
20
|
+
|
21
|
+
Generate API documentation:
|
22
|
+
|
23
|
+
rake yard
|
24
|
+
|
25
|
+
## Using the client
|
26
|
+
|
27
|
+
The `Vault::InvoiceBuilder` API may only be accessed anonymously:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'vault-invoice-builder-client'
|
31
|
+
|
32
|
+
client = Vault::InvoiceBuilder::Client.new(
|
33
|
+
'https://vault-invoice-builder.herokuapp.com')
|
34
|
+
```
|
35
|
+
|
36
|
+
For endpoints that require authentication, HTTP Basic credentials must
|
37
|
+
be supplied in the URL:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
client = Vault::InvoiceBuilder::Client.new(
|
41
|
+
'https://username:password@vault-invoice-builder.herokuapp.com')
|
42
|
+
```
|
43
|
+
|
44
|
+
### Rendering an invoice.
|
45
|
+
|
46
|
+
An invoice contains customer contact and tax details, a list of apps
|
47
|
+
and the charges they've incurred by consuming dyno hours and using
|
48
|
+
addons, a list of charges for products the customer used directly,
|
49
|
+
such as a support contract, and credits that have been applied to
|
50
|
+
cover some or all of the charges on the invoice. An invoice is
|
51
|
+
rendered from a receipt, a JSON representation of app and user charges
|
52
|
+
and credits.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
receipt = {user: 'user123@heroku.com', start_time: …, …}
|
56
|
+
html_content = client.render_html(receipt)
|
57
|
+
```
|
58
|
+
|
59
|
+
### Storing an invoice
|
60
|
+
The `store` method can be used to render an invoice and then store it
|
61
|
+
to S3. The same receipt JSON object is passed and an empty 200 OK
|
62
|
+
response is returned if the request was successful.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
receipt = {user: 'user123@heroku.com', start_time: …, …}
|
66
|
+
response = client.store(receipt)
|
67
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require :default, ENV['RACK_ENV'].to_sym
|
3
|
+
|
4
|
+
require 'excon'
|
5
|
+
require 'yajl/json_gem'
|
6
|
+
|
7
|
+
module Vault
|
8
|
+
module InvoiceBuilder
|
9
|
+
# Client provides a Ruby API to access the `Vault::InvoiceBuilder` HTTP
|
10
|
+
# API.
|
11
|
+
class Client
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'vault-invoice-builder-client/client'
|
17
|
+
require 'vault-invoice-builder-client/version'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Vault::InvoiceBuilder
|
2
|
+
# Client for the `Vault::InvoiceBuilder` HTTP API.
|
3
|
+
class Client
|
4
|
+
# The `Vault::InvoiceBuilder` HTTP API URL.
|
5
|
+
attr_reader :url
|
6
|
+
|
7
|
+
# Instantiate a client.
|
8
|
+
#
|
9
|
+
# @param url [String] The URL to connect to. Include the username and
|
10
|
+
# password to use when connecting. Defaults to the URL defined in the
|
11
|
+
# `VAULT_INVOICE_BUILDER_URL` environment variable if one isn't
|
12
|
+
# explicitly provided.
|
13
|
+
def initialize(url = nil)
|
14
|
+
@url = url || ENV['VAULT_INVOICE_BUILDER_URL']
|
15
|
+
end
|
16
|
+
|
17
|
+
# Render a statement into an HTML invoice.
|
18
|
+
#
|
19
|
+
# @param statement [Hash] An object matching the statement format described in
|
20
|
+
# the `Vault::InvoiceBuilder` README.
|
21
|
+
# @raise [Excon::Errors::HTTPStatusError] Raised if the server returns an
|
22
|
+
# unsuccessful HTTP status code.
|
23
|
+
# @return [String] The rendered HTML invoice.
|
24
|
+
def render_html(statement)
|
25
|
+
connection = Excon.new(@url)
|
26
|
+
response = connection.post(
|
27
|
+
path: "/invoice.html",
|
28
|
+
headers: {'Content-Type' => 'application/json'},
|
29
|
+
body: JSON.generate(statement),
|
30
|
+
expects: [200])
|
31
|
+
response.body
|
32
|
+
end
|
33
|
+
|
34
|
+
# POST a statement to to the proxy-able /statement/:id endpoint
|
35
|
+
#
|
36
|
+
# @param statement [Hash] An object matching the statement format described in
|
37
|
+
# the `Vault::InvoiceBuilder` README.
|
38
|
+
# @raise [Excon::Errors::HTTPStatusError] Raised if the server returns an
|
39
|
+
# unsuccessful HTTP status code.
|
40
|
+
# @return [Excon::Response] The response object.
|
41
|
+
def post(statement)
|
42
|
+
connection = Excon.new(@url)
|
43
|
+
id = statement[:id] || statement['id']
|
44
|
+
response = connection.post(
|
45
|
+
path: "/statement/#{id}",
|
46
|
+
headers: {'Content-Type' => 'application/json'},
|
47
|
+
body: JSON.generate(statement),
|
48
|
+
expects: [200])
|
49
|
+
end
|
50
|
+
|
51
|
+
# @deprecated
|
52
|
+
#
|
53
|
+
# @param statement [Hash] An object matching the statement format described in
|
54
|
+
# the `Vault::InvoiceBuilder` README.
|
55
|
+
# @raise [Excon::Errors::HTTPStatusError] Raised if the server returns an
|
56
|
+
# unsuccessful HTTP status code.
|
57
|
+
# @return [Excon::Response] The response object.
|
58
|
+
def store(statement)
|
59
|
+
connection = Excon.new(@url)
|
60
|
+
response = connection.post(
|
61
|
+
path: '/store',
|
62
|
+
headers: {'Content-Type' => 'application/json'},
|
63
|
+
body: JSON.generate(statement),
|
64
|
+
expects: [200])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/test/client_test.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class ClientTest < Vault::TestCase
|
4
|
+
include Vault::Test::EnvironmentHelpers
|
5
|
+
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
Excon.stubs.clear
|
9
|
+
Excon.defaults[:mock] = true
|
10
|
+
@client = Vault::InvoiceBuilder::Client.new(
|
11
|
+
'https://vault-invoice-builder.herokuapp.com')
|
12
|
+
@statement = {user: 'user123@heroku.com',
|
13
|
+
start_time: Time.utc(2012, 1),
|
14
|
+
stop_time: Time.utc(2012, 2)}
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
# FIXME This is a bit ugly, but Excon doesn't provide a builtin way to
|
19
|
+
# ensure that a request was invoked, so we have to do it ourselves.
|
20
|
+
# Without this, and the Excon.stubs.pop calls in the tests below, tests
|
21
|
+
# will pass if request logic is completely removed from application
|
22
|
+
# code. -jkakar
|
23
|
+
assert(Excon.stubs.empty?, 'Expected HTTP requests were not made.')
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
# Client.new looks for VAULT_INVOICE_BUILDER_URL if none is passed to the
|
28
|
+
# constructor.
|
29
|
+
def test_uses_url_from_environment_by_default
|
30
|
+
url = 'http://example.com'
|
31
|
+
set_env 'VAULT_INVOICE_BUILDER_URL', url
|
32
|
+
@client = Vault::InvoiceBuilder::Client.new
|
33
|
+
assert_equal(url, @client.url)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Client.render_html makes a PUT request to the Vault::InvoiceBuilder HTTP
|
37
|
+
# API, passing the supplied credentials using HTTP basic auth, to report
|
38
|
+
# that usage of a product began at a particular time.
|
39
|
+
def test_render_html
|
40
|
+
content = '<html><body><p>Hello, world!</p></body></html>'
|
41
|
+
Excon.stub(method: :post) do |request|
|
42
|
+
assert_equal('vault-invoice-builder.herokuapp.com:443',
|
43
|
+
request[:host_port])
|
44
|
+
assert_equal("/invoice.html", request[:path])
|
45
|
+
Excon.stubs.pop
|
46
|
+
{status: 200, body: content}
|
47
|
+
end
|
48
|
+
assert_equal(content, @client.render_html(@statement))
|
49
|
+
end
|
50
|
+
|
51
|
+
# Client.render_html raises the appropriate Excon::Errors::HTTPStatusError
|
52
|
+
# if an unsuccessful HTTP status code is returned by the server.
|
53
|
+
def test_render_html_with_unsuccessful_response
|
54
|
+
Excon.stub(method: :post) do |request|
|
55
|
+
Excon.stubs.pop
|
56
|
+
{status: 400, body: 'Bad inputs provided.'}
|
57
|
+
end
|
58
|
+
assert_raises Excon::Errors::BadRequest do
|
59
|
+
@client.render_html(@statement)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Client.store makes a POST request to the Vault::InvoiceBuilder HTTP API,
|
64
|
+
# passing the supplied credentials using HTTP Basic Auth, to which triggers
|
65
|
+
# Vault::InvoiceBuilder to generate the invoice and store it to S3.
|
66
|
+
def test_store
|
67
|
+
Excon.stub(method: :post) do |request|
|
68
|
+
assert_equal('vault-invoice-builder.herokuapp.com:443',
|
69
|
+
request[:host_port])
|
70
|
+
assert_equal('/store', request[:path])
|
71
|
+
assert_equal('application/json', request[:headers]['Content-Type'])
|
72
|
+
Excon.stubs.pop
|
73
|
+
{status: 200}
|
74
|
+
end
|
75
|
+
response = @client.store(@statement)
|
76
|
+
assert_equal(200, response.status)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Client.store raises the appropriate Excon::Errors::HTTPStatusError if an
|
80
|
+
# unsuccessful HTTP status code is returned by the server.
|
81
|
+
def test_store_with_unsuccessful_response
|
82
|
+
Excon.stub(method: :post) do |request|
|
83
|
+
Excon.stubs.pop
|
84
|
+
{status: 400, body: 'Bad inputs provided.'}
|
85
|
+
end
|
86
|
+
assert_raises Excon::Errors::BadRequest do
|
87
|
+
@client.store(@statement)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Client.post makes a POST request to the canonical statement drain API
|
92
|
+
def test_post_with_symbol_id_key
|
93
|
+
@statement[:id] = 1
|
94
|
+
Excon.stub(method: :post) do |request|
|
95
|
+
assert_equal('vault-invoice-builder.herokuapp.com:443',
|
96
|
+
request[:host_port])
|
97
|
+
assert_equal('/statement/1', request[:path])
|
98
|
+
assert_equal('application/json', request[:headers]['Content-Type'])
|
99
|
+
Excon.stubs.pop
|
100
|
+
{status: 200}
|
101
|
+
end
|
102
|
+
response = @client.post(@statement)
|
103
|
+
assert_equal(200, response.status)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Client.post makes a POST request to the canonical statement drain API
|
107
|
+
def test_post_with_string_id_key
|
108
|
+
@statement['id'] = 1
|
109
|
+
Excon.stub(method: :post) do |request|
|
110
|
+
assert_equal('vault-invoice-builder.herokuapp.com:443',
|
111
|
+
request[:host_port])
|
112
|
+
assert_equal('/statement/1', request[:path])
|
113
|
+
assert_equal('application/json', request[:headers]['Content-Type'])
|
114
|
+
Excon.stubs.pop
|
115
|
+
{status: 200}
|
116
|
+
end
|
117
|
+
response = @client.post(@statement)
|
118
|
+
assert_equal(200, response.status)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Client.store raises the appropriate Excon::Errors::HTTPStatusError if an
|
122
|
+
# unsuccessful HTTP status code is returned by the server.
|
123
|
+
def test_post_with_unsuccessful_response
|
124
|
+
Excon.stub(method: :post) do |request|
|
125
|
+
Excon.stubs.pop
|
126
|
+
{status: 400, body: 'Bad inputs provided.'}
|
127
|
+
end
|
128
|
+
assert_raises Excon::Errors::BadRequest do
|
129
|
+
@client.post(@statement)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'vault-invoice-builder-client/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "vault-invoice-builder-client"
|
7
|
+
gem.version = Vault::InvoiceBuilder::Client::VERSION
|
8
|
+
gem.authors = ["Chris Continanza", "Jamu Kakar", "Matthew Manning"]
|
9
|
+
gem.email = ["csquared@heroku.com", "jkakar@heroku.com",
|
10
|
+
"matthew@heroku.com"]
|
11
|
+
gem.description = "Client for Vault::InvoiceBuilder"
|
12
|
+
gem.summary = "A simple wrapper for the Vault::InvoiceBuilder HTTP API"
|
13
|
+
gem.homepage = "https://github.com/heroku/vault-invoice-builder-client"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.test_files = gem.files.grep('^(test|spec|features)/')
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.add_dependency 'excon'
|
20
|
+
gem.add_dependency 'yajl-ruby'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vault-invoice-builder-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Continanza
|
9
|
+
- Jamu Kakar
|
10
|
+
- Matthew Manning
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2013-05-09 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: excon
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ! '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0'
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: yajl-ruby
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
description: Client for Vault::InvoiceBuilder
|
49
|
+
email:
|
50
|
+
- csquared@heroku.com
|
51
|
+
- jkakar@heroku.com
|
52
|
+
- matthew@heroku.com
|
53
|
+
executables: []
|
54
|
+
extensions: []
|
55
|
+
extra_rdoc_files: []
|
56
|
+
files:
|
57
|
+
- .gitignore
|
58
|
+
- .yardopts
|
59
|
+
- Gemfile
|
60
|
+
- Gemfile.lock
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- lib/vault-invoice-builder-client.rb
|
64
|
+
- lib/vault-invoice-builder-client/client.rb
|
65
|
+
- lib/vault-invoice-builder-client/version.rb
|
66
|
+
- test/client_test.rb
|
67
|
+
- test/helper.rb
|
68
|
+
- test/version_test.rb
|
69
|
+
- vault-invoice-builder-client.gemspec
|
70
|
+
homepage: https://github.com/heroku/vault-invoice-builder-client
|
71
|
+
licenses: []
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
hash: -3070326704752709441
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
hash: -3070326704752709441
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.8.23
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: A simple wrapper for the Vault::InvoiceBuilder HTTP API
|
100
|
+
test_files: []
|
101
|
+
has_rdoc:
|