chart_mogul 0.0.1 → 0.1.0

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.
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