chart_mogul 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dacc8e1ab7ea648768a32a8e3cd7a0940d08ba83
4
- data.tar.gz: d3591d6e6a8dea310da2f3d7b19244e44cd7fedf
3
+ metadata.gz: 7d2be0447fd155e52b53b2dec55b2a17cffa455c
4
+ data.tar.gz: df71a2c81fdb91fdab2b922e05887f856d7a35fb
5
5
  SHA512:
6
- metadata.gz: 06209d073ba8e80b49191659e818078fdf5663992e31e986398245e4313e35f3cefeb67662028f4a5bac25e60b745a6da8555f3f2f4808140fb68a8610214082
7
- data.tar.gz: f8dea0e870b94b7fe4c60883418aad0a3ff6b54659b0a01145811b94fa380fda7761e20ff2d9073299ad95f261bf9ad800bbc24c56cdb8a0ed39f7211c2e1c9c
6
+ metadata.gz: 4f03903826ba697eff43e9d1ea3692c03ef53399d0f3e7d3d01e4f0600c07240c284d1f0b6399a226d904d744dccf94f30be801fc8b8536c38d34aa66c3319f3
7
+ data.tar.gz: 5b9859eac58650c90ac7662743680bc9394448897cb466074542fbdf25e45d8b39a38308bec75aba99e14f36f6c8afe2310f6285d58b0fa25916f8953d458f86
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.gem
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # ChartMogul
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/chart_mogul`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ This gem is designed to streamline interaction with the [ChartMogul](https://dev.chartmogul.com) API. The initial focus has been on support for the [Import API](link!!).
6
4
 
7
5
  ## Installation
8
6
 
@@ -22,7 +20,52 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ Credentials are provided in the Account / API area of the ChartMogul application and comprise an `account_token` and `secret_key`.
24
+
25
+ This can be passed in when insantiating a `ChartMogul::Client` instance, eg:
26
+
27
+ ```ruby
28
+ client = ChartMogul::Client.new(account_token: 'token value', secret_key: 'secret value')
29
+ ```
30
+
31
+ If not passed to the constructor the values returned by the `CHART_MOGUL_ACCOUNT_TOKEN` and `CHART_MOGUL_SECRET_KEY` environment variables are used.
32
+
33
+ Methods for access the API are exposed on the `client`.
34
+
35
+ ### Reading data
36
+
37
+ Reading methods, `list_` prefix, are either presented as simple methods that page through all responses from the API and present a fully populated Array of typed objects.
38
+
39
+ ```ruby
40
+ client.list_customers # => [ Import::Customer, Import::Customer ]
41
+ ```
42
+
43
+ and as an iterative version, with an `_each` suffix, that expects a block. Useful for those situations where you're dealing with a lot of records and don't want them necessarily all in memory. This again handles the paging transparently.
44
+
45
+ The block is yielded to with a typed object.
46
+
47
+ ```ruby
48
+ client.list_customers_each do |customer|
49
+ # do something with the Import::Customer here
50
+ end
51
+ ```
52
+
53
+ ### Importing data
54
+
55
+ Data records are imported by passing a Hash of attributes to a `create_` prefixed method.
56
+
57
+ ```ruby
58
+ client.create_plan({
59
+ data_source_uuid: "ds_2323232",
60
+ name: "Top Plan",
61
+ interval_count: 1,
62
+ interval_unit: :month
63
+ })
64
+ ```
65
+
66
+ Dates and times are expected as `Time` objects. The gem handles the formatting required by the ChartMogul API.
67
+
68
+ Where possible pre request validation is also handled by the gem. `ArgumentErrors` with a description of the variable are raised in the event that pre submit validation fails.
26
69
 
27
70
  ## Development
28
71
 
@@ -32,7 +75,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
75
 
33
76
  ## Contributing
34
77
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/chart_mogul. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
78
+ Bug reports and pull requests are welcome on GitHub at https://github.com/adambird/chart_mogul. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
36
79
 
37
80
 
38
81
  ## License
@@ -30,6 +30,10 @@ module ChartMogul
30
30
  end
31
31
  end
32
32
 
33
+ def credentials?
34
+ account_token && secret_key
35
+ end
36
+
33
37
  def ping?
34
38
  response = connection.get("/v1/ping")
35
39
  preprocess_response(response)[:data] == 'pong!'
@@ -37,7 +41,9 @@ module ChartMogul
37
41
 
38
42
  def paged_get(path, params, data_field)
39
43
  begin
40
- result = preprocess_response(connection.get(path, params))
44
+ params[:page_number] = 1 unless params[:page_number]
45
+ response = connection.get(path, params)
46
+ result = preprocess_response(response)
41
47
  yield result[data_field]
42
48
  params[:page_number] = result[:current_page]
43
49
  end while params[:page_number] < result[:total_pages]
@@ -51,23 +57,33 @@ module ChartMogul
51
57
  raise UnauthorizedError.new
52
58
  when 422
53
59
  result = JSON.parse(response.body, symbolize_names: true)
54
- raise ValidationError.new(result[:errors])
60
+ raise ValidationError.new(result)
55
61
  else
56
62
  puts response.inspect
57
63
  raise StandardError.new("#{response.status} #{response.body.slice(0,50)}")
58
64
  end
59
65
  end
60
66
 
67
+ def format_datetime(value)
68
+ value.strftime("%Y-%m-%d %H:%M:%S")
69
+ end
70
+
61
71
  class UnauthorizedError < StandardError
62
72
  end
63
73
 
64
74
  class ValidationError < StandardError
65
75
 
66
76
  attr_reader :errors
77
+ attr_reader :body
67
78
 
68
- def initialize(errors)
69
- @errors = errors
70
- super("validation errors for #{errors.keys.join(', ')}")
79
+ def initialize(result)
80
+ @body = result
81
+ if result[:errors]
82
+ @errors = result[:errors]
83
+ super("validation errors for #{@errors.keys.join(', ')}")
84
+ else
85
+ super("validation errors #{@body}")
86
+ end
71
87
  end
72
88
 
73
89
  end
@@ -0,0 +1,73 @@
1
+ module ChartMogul
2
+ module Import
3
+ class Invoice
4
+
5
+ attr_reader :uuid
6
+ attr_reader :date
7
+ attr_reader :external_id
8
+ attr_reader :currency
9
+ attr_reader :due_date
10
+ attr_reader :line_items
11
+ attr_reader :transactions
12
+
13
+ class LineItem
14
+ attr_reader :uuid
15
+ attr_reader :external_id
16
+ attr_reader :type
17
+ attr_reader :subscription_uuid
18
+ attr_reader :plan_uuid
19
+ attr_reader :prorated
20
+ attr_reader :service_period_start
21
+ attr_reader :service_period_end
22
+ attr_reader :amount_in_cents
23
+ attr_reader :quantity
24
+ attr_reader :discount_code
25
+ attr_reader :discount_amount_in_cents
26
+ attr_reader :tax_amount_in_cents
27
+
28
+ def initialize(args)
29
+ %i{uuid external_id type subscription_uuid plan_uuid prorated amount_in_cents quantity discount_code discount_amount_in_cents tax_amount_in_cents}
30
+ .each do |key|
31
+ instance_variable_set("@#{key}", args[key])
32
+ end
33
+
34
+ %i{service_period_start service_period_end}
35
+ .each do |key|
36
+ instance_variable_set("@#{key}", Time.parse(args[key])) if args[key]
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+
43
+ class Transaction
44
+ attr_reader :uuid
45
+ attr_reader :external_id
46
+ attr_reader :type
47
+ attr_reader :date
48
+ attr_reader :result
49
+
50
+ def initialize(args)
51
+ %i{uuid external_id type result}
52
+ .each do |key|
53
+ instance_variable_set("@#{key}", args[key])
54
+ end
55
+
56
+ instance_variable_set("@#{:date}", Time.parse(args[:date])) if args[:date]
57
+ end
58
+
59
+ end
60
+
61
+ def initialize(args)
62
+ @uuid = args[:uuid]
63
+ @external_id = args[:external_id]
64
+ @currency = args[:currency]
65
+ @date = Time.parse(args[:date]) if args[:date]
66
+ @due_date = Time.parse(args[:due_date]) if args[:due_date]
67
+
68
+ @line_items = args[:line_items].map { |li| LineItem.new(li) }
69
+ @transactions = args[:transactions].map { |li| Transaction.new(li) }
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,6 +1,7 @@
1
1
  require_relative 'import/customer'
2
2
  require_relative 'import/data_source'
3
3
  require_relative 'import/plan'
4
+ require_relative 'import/invoice'
4
5
 
5
6
  module ChartMogul
6
7
  module ImportApi
@@ -70,7 +71,7 @@ module ChartMogul
70
71
  # Returns an Enumerable that will yield a ChartMogul::Import::Customer for
71
72
  # each record
72
73
  def list_customers_each(options={}, &block)
73
- params = { page_number: 1 }
74
+ params = {}
74
75
  params[:data_source_uuid] = options[:data_source_uuid] if options[:data_source_uuid]
75
76
 
76
77
  paged_get("/v1/import/customers", params, :customers) do |customers|
@@ -80,13 +81,13 @@ module ChartMogul
80
81
  end
81
82
  end
82
83
 
83
- # Public - create a Customer
84
+ # Public - import a Customer
84
85
  #
85
86
  # args - Hash of params see https://dev.chartmogul.com/docs/customers
86
87
  # Mandatory: :data_source_uuid, :external_id, :name
87
88
  #
88
89
  # Returns a ChartMogul::Import::Customer
89
- def create_customer(args)
90
+ def import_customer(args)
90
91
  [:data_source_uuid, :external_id, :name].each do |attribute|
91
92
  refute_blank! args[attribute], attribute
92
93
  end
@@ -127,7 +128,7 @@ module ChartMogul
127
128
  # Returns an Enumerable that will yield a ChartMogul::Import::Plan for
128
129
  # each record
129
130
  def list_plans_each(options={}, &block)
130
- params = { page_number: 1 }
131
+ params = {}
131
132
  params[:data_source_uuid] = options[:data_source_uuid] if options[:data_source_uuid]
132
133
 
133
134
  paged_get("/v1/import/plans", params, :plans) do |plans|
@@ -137,13 +138,13 @@ module ChartMogul
137
138
  end
138
139
  end
139
140
 
140
- # Public - create a Plan
141
+ # Public - import a Plan
141
142
  #
142
143
  # args - Hash of params see https://dev.chartmogul.com/docs/plans
143
144
  # Mandatory: :data_source_uuid, :name, :interval_count, :interval_unit
144
145
  #
145
146
  # Returns a ChartMogul::Import::Plan
146
- def create_plan(args)
147
+ def import_plan(args)
147
148
  [:data_source_uuid, :name, :interval_unit, :interval_count].each do |attribute|
148
149
  refute_blank! args[attribute], attribute
149
150
  end
@@ -158,5 +159,92 @@ module ChartMogul
158
159
 
159
160
  Import::Plan.new(preprocess_response(response))
160
161
  end
162
+
163
+ # Public - import a single Invoice. Convenience method that
164
+ # maps the output (and validation errors) to a single operation
165
+ #
166
+ # customer_id - ChartMogul id for the customer
167
+ # invoice - Hash of params see https://dev.chartmogul.com/docs/invoices
168
+ # See invoice_invoices for mandatory attributes
169
+ #
170
+ # Returns an Array of ChartMogul::Import::Invoice
171
+ def import_invoice(customer_id, invoice)
172
+ invoices = import_invoices(customer_id, [ invoice ])
173
+ invoices.first
174
+
175
+ rescue ChartMogul::Client::ValidationError => e
176
+ # restructure ValidationError to map the single invoice error that was returned
177
+ if e.body[:invoices]
178
+ raise ChartMogul::Client::ValidationError.new(e.body[:invoices].first)
179
+ else
180
+ raise
181
+ end
182
+ end
183
+
184
+ # Public - import Invoices
185
+ #
186
+ # customer_id - ChartMogul id for the customer
187
+ # invoices - Array of Hash of params see https://dev.chartmogul.com/docs/invoices
188
+ # Mandatory: :external_id, :date, :currency, :line_items
189
+ #
190
+ # Returns an Array of ChartMogul::Import::Invoice
191
+ def import_invoices(customer_id, invoices)
192
+ refute_blank! customer_id, "customer_id"
193
+ refute! invoices.nil? && invoices.empty?, "invoices required"
194
+
195
+ args = { invoices: invoices }
196
+
197
+ args[:invoices].each do |invoice|
198
+ [:external_id, :date, :currency].each do |attribute|
199
+ refute_blank! invoice[attribute], attribute
200
+ end
201
+
202
+ invoice[:date] = format_datetime(invoice[:date])
203
+
204
+ assert! invoice[:line_items] && invoice[:line_items].any?, "line_items is required"
205
+
206
+ invoice[:line_items].each do |line_item|
207
+ line_item[:service_period_start] = format_datetime(line_item[:service_period_start]) if line_item[:service_period_start]
208
+ line_item[:service_period_end] = format_datetime(line_item[:service_period_end]) if line_item[:service_period_end]
209
+ assert! line_item[:quantity].nil? || line_item[:quantity] > 0, "line_item quantity must be greater than zero if specified"
210
+ end
211
+
212
+ end
213
+
214
+ response = connection.post do |request|
215
+ request.url "/v1/import/customers/#{customer_id}/invoices"
216
+ request.headers['Content-Type'] = "application/json"
217
+ request.body = args.to_json
218
+ end
219
+
220
+ preprocess_response(response)[:invoices].map { |i| Import::Invoice.new(i) }
221
+ end
222
+
223
+ # Public - list of Customer invoices
224
+ # customer_id - ChartMogul id for the customer
225
+ #
226
+ # Returns an Array of ChartMogul::Import::Invoice
227
+ def list_invoices(customer_id)
228
+ invoices = []
229
+ list_invoices_each(customer_id) { |i| invoices << i }
230
+ invoices
231
+ end
232
+
233
+ # Public - iterate through all invoices
234
+ #
235
+ # customer_id - ChartMogul id for the customer
236
+ #
237
+ # Returns an Enumerable that will yield a ChartMogul::Import::Invoice for
238
+ # each record
239
+ def list_invoices_each(customer_id, &block)
240
+ refute_blank! customer_id, "customer_id"
241
+
242
+ paged_get("/v1/import/customers/#{customer_id}/invoices", {}, :invoices) do |invoices|
243
+ invoices.each do |invoice|
244
+ yield Import::Invoice.new(invoice)
245
+ end
246
+ end
247
+ end
248
+
161
249
  end
162
250
  end
@@ -1,3 +1,3 @@
1
1
  module ChartMogul
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chart_mogul
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Bird
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-25 00:00:00.000000000 Z
11
+ date: 2016-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -103,6 +103,7 @@ files:
103
103
  - lib/chart_mogul/client.rb
104
104
  - lib/chart_mogul/import/customer.rb
105
105
  - lib/chart_mogul/import/data_source.rb
106
+ - lib/chart_mogul/import/invoice.rb
106
107
  - lib/chart_mogul/import/plan.rb
107
108
  - lib/chart_mogul/import_api.rb
108
109
  - lib/chart_mogul/version.rb