chartmogul-ruby 1.5.1 → 1.6.6

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -1
  4. data/Gemfile +2 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +5 -3
  7. data/Rakefile +2 -0
  8. data/bin/console +1 -0
  9. data/chartmogul-ruby.gemspec +21 -17
  10. data/fixtures/vcr_cassettes/ChartMogul_APIResource/connection/works_in_a_threaded_environment.yml +112 -0
  11. data/fixtures/vcr_cassettes/ChartMogul_APIResource/connection/works_when_credentials_are_updated.yml +77 -0
  12. data/fixtures/vcr_cassettes/ChartMogul_Customer/API_Interactions/updates_customer_using_class_method.yml +53 -0
  13. data/fixtures/vcr_cassettes/ChartMogul_CustomerInvoices/API_Interactions/correctly_interracts_with_the_API.yml +148 -109
  14. data/fixtures/vcr_cassettes/ChartMogul_Plan/API_Interactions/updates_existing_plan_using_class_method.yml +164 -0
  15. data/fixtures/vcr_cassettes/ChartMogul_PlanGroup/API_interactions/updates_existing_plan_group_name_via_class_method.yml +297 -0
  16. data/lib/chartmogul.rb +8 -2
  17. data/lib/chartmogul/api/actions/all.rb +2 -0
  18. data/lib/chartmogul/api/actions/create.rb +2 -0
  19. data/lib/chartmogul/api/actions/custom.rb +2 -0
  20. data/lib/chartmogul/api/actions/destroy.rb +2 -0
  21. data/lib/chartmogul/api/actions/retrieve.rb +2 -0
  22. data/lib/chartmogul/api/actions/update.rb +22 -0
  23. data/lib/chartmogul/api_resource.rb +21 -12
  24. data/lib/chartmogul/concerns/entries.rb +2 -0
  25. data/lib/chartmogul/concerns/pageable.rb +2 -0
  26. data/lib/chartmogul/concerns/pageable2.rb +2 -0
  27. data/lib/chartmogul/concerns/summary.rb +2 -0
  28. data/lib/chartmogul/config_attributes.rb +7 -1
  29. data/lib/chartmogul/configuration.rb +3 -0
  30. data/lib/chartmogul/customer.rb +2 -0
  31. data/lib/chartmogul/customer_invoices.rb +11 -0
  32. data/lib/chartmogul/data_source.rb +2 -0
  33. data/lib/chartmogul/enrichment/customer.rb +2 -0
  34. data/lib/chartmogul/errors/chartmogul_error.rb +2 -0
  35. data/lib/chartmogul/errors/configuration_error.rb +2 -0
  36. data/lib/chartmogul/errors/forbidden_error.rb +2 -0
  37. data/lib/chartmogul/errors/not_found_error.rb +2 -0
  38. data/lib/chartmogul/errors/resource_invalid_error.rb +2 -0
  39. data/lib/chartmogul/errors/schema_invalid_error.rb +2 -0
  40. data/lib/chartmogul/errors/server_error.rb +2 -0
  41. data/lib/chartmogul/errors/unauthorized_error.rb +2 -0
  42. data/lib/chartmogul/invoice.rb +2 -0
  43. data/lib/chartmogul/line_items/one_time.rb +2 -0
  44. data/lib/chartmogul/line_items/subscription.rb +2 -0
  45. data/lib/chartmogul/metrics/activity.rb +2 -0
  46. data/lib/chartmogul/metrics/all_key_metrics.rb +2 -0
  47. data/lib/chartmogul/metrics/arpa.rb +2 -0
  48. data/lib/chartmogul/metrics/arr.rb +2 -0
  49. data/lib/chartmogul/metrics/asp.rb +2 -0
  50. data/lib/chartmogul/metrics/base.rb +6 -2
  51. data/lib/chartmogul/metrics/customer_churn_rate.rb +2 -0
  52. data/lib/chartmogul/metrics/customer_count.rb +2 -0
  53. data/lib/chartmogul/metrics/ltv.rb +2 -0
  54. data/lib/chartmogul/metrics/mrr.rb +2 -0
  55. data/lib/chartmogul/metrics/mrr_churn_rate.rb +2 -0
  56. data/lib/chartmogul/metrics/subscription.rb +2 -0
  57. data/lib/chartmogul/object.rb +2 -0
  58. data/lib/chartmogul/ping.rb +2 -0
  59. data/lib/chartmogul/plan.rb +2 -0
  60. data/lib/chartmogul/plan_group.rb +2 -0
  61. data/lib/chartmogul/plan_groups/plans.rb +2 -0
  62. data/lib/chartmogul/resource_path.rb +6 -1
  63. data/lib/chartmogul/subscription.rb +2 -0
  64. data/lib/chartmogul/summary.rb +2 -0
  65. data/lib/chartmogul/transactions/payment.rb +2 -0
  66. data/lib/chartmogul/transactions/refund.rb +2 -0
  67. data/lib/chartmogul/utils/hash_snake_caser.rb +2 -0
  68. data/lib/chartmogul/utils/json_parser.rb +11 -1
  69. data/lib/chartmogul/version.rb +3 -1
  70. metadata +64 -17
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'time'
2
4
  require 'json'
3
5
  require 'faraday'
@@ -69,18 +71,22 @@ require 'chartmogul/metrics/subscription'
69
71
  require 'chartmogul/enrichment/customer'
70
72
 
71
73
  module ChartMogul
72
- API_BASE = 'https://api.chartmogul.com'.freeze
74
+ API_BASE = 'https://api.chartmogul.com'
73
75
  MAX_RETRIES = 20
76
+ CONFIG_THREAD_KEY = 'chartmogul_ruby.config'
74
77
 
75
78
  class << self
76
79
  extend ConfigAttributes
77
80
 
81
+
78
82
  def config
79
- @config ||= ChartMogul::Configuration.new
83
+ Thread.current[CONFIG_THREAD_KEY] = ChartMogul::Configuration.new if Thread.current[CONFIG_THREAD_KEY].nil?
84
+ Thread.current[CONFIG_THREAD_KEY]
80
85
  end
81
86
 
82
87
  config_accessor :account_token
83
88
  config_accessor :secret_key
84
89
  config_accessor :max_retries, MAX_RETRIES
90
+ config_accessor :api_base, API_BASE
85
91
  end
86
92
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module API
3
5
  module Actions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module API
3
5
  module Actions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module API
3
5
  module Actions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module API
3
5
  module Actions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module API
3
5
  module Actions
@@ -1,7 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module API
3
5
  module Actions
4
6
  module Update
7
+ def self.included(base)
8
+ base.extend ClassMethods
9
+ end
10
+
5
11
  def update!
6
12
  resp = handling_errors do
7
13
  connection.patch("#{resource_path.apply(instance_attributes)}/#{uuid}") do |req|
@@ -13,6 +19,22 @@ module ChartMogul
13
19
 
14
20
  assign_all_attributes(json)
15
21
  end
22
+
23
+ module ClassMethods
24
+ def update!(uuid, attributes = {})
25
+ resource = new(attributes)
26
+
27
+ resp = handling_errors do
28
+ connection.patch("#{resource_path.apply(attributes)}/#{uuid}") do |req|
29
+ req.headers['Content-Type'] = 'application/json'
30
+ req.body = JSON.dump(resource.serialize_for_write)
31
+ end
32
+ end
33
+ json = ChartMogul::Utils::JSONParser.parse(resp.body)
34
+
35
+ new_from_json(json)
36
+ end
37
+ end
16
38
  end
17
39
  end
18
40
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
 
3
5
  module ChartMogul
@@ -13,6 +15,7 @@ module ChartMogul
13
15
  INTERVAL_RANDOMNESS = 0.5
14
16
  INTERVAL = 1
15
17
  MAX_INTERVAL = 60
18
+ THREAD_CONNECTION_KEY = 'chartmogul_ruby.api_resource.connection'
16
19
 
17
20
  class << self; attr_reader :resource_path, :resource_name, :resource_root_key end
18
21
 
@@ -29,22 +32,15 @@ module ChartMogul
29
32
  end
30
33
 
31
34
  def self.connection
32
- @connection ||= Faraday.new(url: ChartMogul::API_BASE) do |faraday|
33
- faraday.use Faraday::Request::BasicAuthentication, ChartMogul.account_token, ChartMogul.secret_key
34
- faraday.use Faraday::Response::RaiseError
35
- faraday.request :retry, max: ChartMogul.max_retries, retry_statuses: RETRY_STATUSES,
36
- max_interval: MAX_INTERVAL, backoff_factor: BACKOFF_FACTOR,
37
- interval_randomness: INTERVAL_RANDOMNESS, interval: INTERVAL, exceptions: RETRY_EXCEPTIONS
38
- faraday.use Faraday::Adapter::NetHttp
39
- end
35
+ Thread.current[THREAD_CONNECTION_KEY] ||= build_connection
40
36
  end
41
37
 
42
38
  def self.handling_errors
43
39
  yield
44
- rescue Faraday::ClientError => exception
45
- exception.response ? handle_request_error(exception) : handle_other_error(exception)
46
- rescue => exception
47
- handle_other_error(exception)
40
+ rescue Faraday::ClientError, Faraday::ServerError => e
41
+ e.response ? handle_request_error(e) : handle_other_error(e)
42
+ rescue StandardError => e
43
+ handle_other_error(e)
48
44
  end
49
45
 
50
46
  def self.handle_request_error(exception)
@@ -80,5 +76,18 @@ module ChartMogul
80
76
  end
81
77
 
82
78
  def_delegators 'self.class', :resource_path, :resource_name, :resource_root_key, :connection, :handling_errors
79
+
80
+ private
81
+
82
+ def self.build_connection
83
+ Faraday.new(url: ChartMogul.api_base) do |faraday|
84
+ faraday.use Faraday::Request::BasicAuthentication, ChartMogul.account_token, ChartMogul.secret_key
85
+ faraday.use Faraday::Response::RaiseError
86
+ faraday.request :retry, max: ChartMogul.max_retries, retry_statuses: RETRY_STATUSES,
87
+ max_interval: MAX_INTERVAL, backoff_factor: BACKOFF_FACTOR,
88
+ interval_randomness: INTERVAL_RANDOMNESS, interval: INTERVAL, exceptions: RETRY_EXCEPTIONS
89
+ faraday.adapter Faraday::Adapter::NetHttp
90
+ end
91
+ end
83
92
  end
84
93
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Concerns
3
5
  module Entries
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Concerns
3
5
  module Pageable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Concerns
3
5
  module Pageable2
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Concerns
3
5
  module Summary
@@ -1,14 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module ConfigAttributes
3
5
  def config_accessor(attribute, default_value = nil)
4
6
  define_method(attribute) do
5
7
  attr = config.send(attribute) || default_value
6
- raise ConfigurationError, "Configuration for #{attribute} not set" if attr.nil?
8
+ if attr.nil?
9
+ raise ConfigurationError, "Configuration for #{attribute} not set"
10
+ end
11
+
7
12
  attr
8
13
  end
9
14
 
10
15
  define_method("#{attribute}=") do |val|
11
16
  config.send("#{attribute}=", val)
17
+ Thread.current[ChartMogul::APIResource::THREAD_CONNECTION_KEY] = nil
12
18
  end
13
19
  end
14
20
  end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class Configuration
3
5
  attr_accessor :account_token
4
6
  attr_accessor :secret_key
5
7
  attr_accessor :max_retries
8
+ attr_accessor :api_base
6
9
  end
7
10
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class Customer < APIResource
3
5
  set_resource_name 'Customer'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
 
3
5
  module ChartMogul
@@ -24,6 +26,15 @@ module ChartMogul
24
26
  super(options.merge(customer_uuid: customer_uuid))
25
27
  end
26
28
 
29
+ def self.destroy_all!(data_source_uuid, customer_uuid)
30
+ path = ChartMogul::ResourcePath.new('v1/data_sources/:data_source_uuid/customers/:customer_uuid/invoices')
31
+ handling_errors do
32
+ connection.delete(path.apply(data_source_uuid: data_source_uuid, customer_uuid: customer_uuid))
33
+ end
34
+ true
35
+ end
36
+
37
+
27
38
  def_delegators :invoices, :each, :[], :<<, :size, :length, :empty?, :first
28
39
 
29
40
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class DataSource < APIResource
3
5
  set_resource_name 'Data Source'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Enrichment
3
5
  # <b>DEPRECATED:</b> Please use <tt>ChartMogul/Customer</tt> instead.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class ChartMogulError < StandardError
3
5
  attr_reader :error_message, :response, :http_status
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class ConfigurationError < ChartMogulError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class ForbiddenError < ChartMogulError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class NotFoundError < ChartMogulError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class ResourceInvalidError < ChartMogulError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class SchemaInvalidError < ChartMogulError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class ServerError < ChartMogulError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class UnauthorizedError < ChartMogulError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  class Invoice < APIResource
3
5
  set_resource_name 'Invoice'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module LineItems
3
5
  class OneTime < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module LineItems
3
5
  class Subscription < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class Activity < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class AllKeyMetric < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class ARPA < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class ARR < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class ASP < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  def self.all(options = {})
@@ -40,11 +42,13 @@ module ChartMogul
40
42
 
41
43
  def self.preprocess_params(options)
42
44
  %i[start_date end_date].each do |param_name|
43
- options[param_name.to_s.tr('_', '-')] = options.delete(param_name) if options[param_name]
45
+ if options[param_name]
46
+ options[param_name.to_s.tr('_', '-')] = options.delete(param_name)
47
+ end
44
48
  end
45
49
 
46
50
  %i[geo plans].each do |param_name|
47
- if options[param_name] && options[param_name].is_a?(Array)
51
+ if options[param_name]&.is_a?(Array)
48
52
  options[param_name] = options[param_name].join(',')
49
53
  end
50
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class CustomerChurnRate < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class CustomerCount < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class LTV < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class MRR < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class MRRChurnRate < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ChartMogul
2
4
  module Metrics
3
5
  class Subscription < ChartMogul::Object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module ChartMogul