paddle 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +11 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +67 -2
  5. data/README.md +51 -3
  6. data/lib/paddle/classic/client.rb +0 -1
  7. data/lib/paddle/classic/resource.rb +1 -1
  8. data/lib/paddle/classic/resources/charges.rb +1 -3
  9. data/lib/paddle/classic/resources/coupons.rb +6 -8
  10. data/lib/paddle/classic/resources/licenses.rb +1 -3
  11. data/lib/paddle/classic/resources/modifiers.rb +4 -6
  12. data/lib/paddle/classic/resources/pay_links.rb +0 -2
  13. data/lib/paddle/classic/resources/payments.rb +3 -5
  14. data/lib/paddle/classic/resources/plans.rb +2 -4
  15. data/lib/paddle/classic/resources/products.rb +0 -2
  16. data/lib/paddle/classic/resources/transactions.rb +0 -2
  17. data/lib/paddle/classic/resources/users.rb +7 -9
  18. data/lib/paddle/classic/resources/webhooks.rb +0 -2
  19. data/lib/paddle/client.rb +36 -46
  20. data/lib/paddle/collection.rb +12 -0
  21. data/lib/paddle/configuration.rb +1 -3
  22. data/lib/paddle/error.rb +123 -0
  23. data/lib/paddle/models/address.rb +1 -5
  24. data/lib/paddle/models/adjustment.rb +1 -5
  25. data/lib/paddle/models/business.rb +1 -5
  26. data/lib/paddle/models/customer.rb +1 -5
  27. data/lib/paddle/models/discount.rb +1 -5
  28. data/lib/paddle/models/event.rb +0 -4
  29. data/lib/paddle/models/event_type.rb +0 -4
  30. data/lib/paddle/models/notification.rb +0 -4
  31. data/lib/paddle/models/notification_setting.rb +1 -5
  32. data/lib/paddle/models/price.rb +1 -5
  33. data/lib/paddle/models/pricing_preview.rb +1 -5
  34. data/lib/paddle/models/product.rb +1 -5
  35. data/lib/paddle/models/report.rb +2 -6
  36. data/lib/paddle/models/subscription.rb +3 -7
  37. data/lib/paddle/models/transaction.rb +4 -8
  38. data/lib/paddle/object.rb +22 -1
  39. data/lib/paddle/version.rb +1 -1
  40. data/lib/paddle.rb +2 -2
  41. data/paddle.gemspec +3 -3
  42. metadata +8 -7
data/lib/paddle/error.rb CHANGED
@@ -1,4 +1,127 @@
1
1
  module Paddle
2
2
  class Error < StandardError
3
+ attr_reader :http_status_code
4
+ attr_reader :paddle_error_code
5
+ attr_reader :paddle_error_message
6
+
7
+ def initialize(response_body, http_status_code)
8
+ @response_body = response_body
9
+ @http_status_code = http_status_code
10
+ set_paddle_error_values
11
+ super(build_message)
12
+ end
13
+
14
+ private
15
+
16
+ def set_paddle_error_values
17
+ @paddle_error_code = @response_body.dig("error", "code")
18
+ @paddle_error_message = @response_body.dig("error", "detail")
19
+ end
20
+
21
+ def error_message
22
+ @paddle_error_message || @response_body.dig("error", "code")
23
+ rescue NoMethodError
24
+ "An unknown error occurred."
25
+ end
26
+
27
+ def build_message
28
+ if paddle_error_code.nil?
29
+ return "Error #{@http_status_code}: #{error_message}"
30
+ end
31
+ "Error #{@http_status_code}: #{error_message} '#{paddle_error_code}'"
32
+ end
33
+ end
34
+
35
+ class BadRequestError < Error
36
+ private
37
+
38
+ def error_message
39
+ "Your request was malformed."
40
+ end
41
+ end
42
+
43
+ class AuthenticationMissingError < Error
44
+ private
45
+
46
+ def error_message
47
+ "You did not supply valid authentication credentials."
48
+ end
49
+ end
50
+
51
+ class ForbiddenError < Error
52
+ private
53
+
54
+ def error_message
55
+ "You are not allowed to perform that action."
56
+ end
57
+ end
58
+
59
+ class EntityNotFoundError < Error
60
+ private
61
+
62
+ def error_message
63
+ "No results were found for your request."
64
+ end
65
+ end
66
+
67
+ class ConflictError < Error
68
+ private
69
+
70
+ def error_message
71
+ "Your request was a conflict."
72
+ end
73
+ end
74
+
75
+ class TooManyRequestsError < Error
76
+ private
77
+
78
+ def error_message
79
+ "Your request exceeded the API rate limit."
80
+ end
81
+ end
82
+
83
+ class InternalError < Error
84
+ private
85
+
86
+ def error_message
87
+ "We were unable to perform the request due to server-side problems."
88
+ end
89
+ end
90
+
91
+ class ServiceUnavailableError < Error
92
+ private
93
+
94
+ def error_message
95
+ "You have been rate limited for sending more than 20 requests per second."
96
+ end
97
+ end
98
+
99
+ class NotImplementedError < Error
100
+ private
101
+
102
+ def error_message
103
+ "This resource has not been implemented."
104
+ end
105
+ end
106
+
107
+
108
+ class ErrorFactory
109
+ HTTP_ERROR_MAP = {
110
+ 400 => BadRequestError,
111
+ 401 => AuthenticationMissingError,
112
+ 403 => ForbiddenError,
113
+ 404 => EntityNotFoundError,
114
+ 409 => ConflictError,
115
+ 429 => TooManyRequestsError,
116
+ 500 => InternalError,
117
+ 503 => ServiceUnavailableError,
118
+ 501 => NotImplementedError
119
+ }.freeze
120
+
121
+ def self.create(response_body, http_status_code)
122
+ status = http_status_code
123
+ error_class = HTTP_ERROR_MAP[status] || Error
124
+ error_class.new(response_body, http_status_code) if error_class
125
+ end
3
126
  end
4
127
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Address < Object
3
-
4
3
  class << self
5
-
6
4
  def list(customer:, **params)
7
5
  response = Client.get_request("customers/#{customer}/addresses", params: params)
8
6
  Collection.from_response(response, type: Address)
9
7
  end
10
8
 
11
9
  def create(customer:, country_code:, postal_code:, **params)
12
- attrs = {country_code: country_code, postal_code: postal_code}
10
+ attrs = { country_code: country_code, postal_code: postal_code }
13
11
  response = Client.post_request("customers/#{customer}/addresses", body: attrs.merge(params))
14
12
  Address.new(response.body["data"])
15
13
  end
@@ -23,8 +21,6 @@ module Paddle
23
21
  response = Client.patch_request("customers/#{customer}/addresses/#{id}", body: params)
24
22
  Address.new(response.body["data"])
25
23
  end
26
-
27
24
  end
28
-
29
25
  end
30
26
  end
@@ -1,20 +1,16 @@
1
1
  module Paddle
2
2
  class Adjustment < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("adjustments", params: params)
8
6
  Collection.from_response(response, type: Adjustment)
9
7
  end
10
8
 
11
9
  def create(transaction_id:, action:, reason:, items:, **params)
12
- attrs = {transaction_id: transaction_id, action: action, reason: reason, items: items}
10
+ attrs = { transaction_id: transaction_id, action: action, reason: reason, items: items }
13
11
  response = Client.post_request("adjustments", body: attrs.merge(params))
14
12
  Adjustment.new(response.body["data"])
15
13
  end
16
-
17
14
  end
18
-
19
15
  end
20
16
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Business < Object
3
-
4
3
  class << self
5
-
6
4
  def list(customer:, **params)
7
5
  response = Client.get_request("customers/#{customer}/businesses", params: params)
8
6
  Collection.from_response(response, type: Business)
9
7
  end
10
8
 
11
9
  def create(customer:, name:, **params)
12
- attrs = {name: name}
10
+ attrs = { name: name }
13
11
  response = Client.post_request("customers/#{customer}/businesses", body: attrs.merge(params))
14
12
  Business.new(response.body["data"])
15
13
  end
@@ -23,8 +21,6 @@ module Paddle
23
21
  response = Client.patch_request("customers/#{customer}/businesses/#{id}", body: params)
24
22
  Business.new(response.body["data"])
25
23
  end
26
-
27
24
  end
28
-
29
25
  end
30
26
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Customer < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("customers", params: params)
8
6
  Collection.from_response(response, type: Customer)
9
7
  end
10
8
 
11
9
  def create(email:, **params)
12
- attrs = {email: email.gsub(/\s+/, "")}
10
+ attrs = { email: email.gsub(/\s+/, "") }
13
11
  response = Client.post_request("customers", body: attrs.merge(params))
14
12
  Customer.new(response.body["data"])
15
13
  end
@@ -28,8 +26,6 @@ module Paddle
28
26
  response = Client.get_request("customers/#{id}/credit-balances")
29
27
  CreditBalance.new(response.body["data"][0])
30
28
  end
31
-
32
29
  end
33
-
34
30
  end
35
31
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Discount < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("discounts", params: params)
8
6
  Collection.from_response(response, type: Discount)
9
7
  end
10
8
 
11
9
  def create(amount:, description:, type:, **params)
12
- attrs = {amount: amount, description: description, type: type}
10
+ attrs = { amount: amount, description: description, type: type }
13
11
  response = Client.post_request("discounts", body: attrs.merge(params))
14
12
  Discount.new(response.body["data"])
15
13
  end
@@ -23,8 +21,6 @@ module Paddle
23
21
  response = Client.patch_request("discounts/#{id}", body: params)
24
22
  Discount.new(response.body["data"])
25
23
  end
26
-
27
24
  end
28
-
29
25
  end
30
26
  end
@@ -1,14 +1,10 @@
1
1
  module Paddle
2
2
  class Event < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("events", params: params)
8
6
  Collection.from_response(response, type: Event)
9
7
  end
10
-
11
8
  end
12
-
13
9
  end
14
10
  end
@@ -1,14 +1,10 @@
1
1
  module Paddle
2
2
  class EventType < Object
3
-
4
3
  class << self
5
-
6
4
  def list
7
5
  response = Client.get_request("event-types")
8
6
  Collection.from_response(response, type: EventType)
9
7
  end
10
-
11
8
  end
12
-
13
9
  end
14
10
  end
@@ -1,8 +1,6 @@
1
1
  module Paddle
2
2
  class Notification < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("notifications", params: params)
8
6
  Collection.from_response(response, type: Notification)
@@ -23,8 +21,6 @@ module Paddle
23
21
  response = Client.get_request("notifications/#{id}/logs", params: params)
24
22
  Collection.from_response(response, type: NotificationLog)
25
23
  end
26
-
27
24
  end
28
-
29
25
  end
30
26
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class NotificationSetting < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("notification-settings", params: params)
8
6
  Collection.from_response(response, type: NotificationSetting)
9
7
  end
10
8
 
11
9
  def create(description:, destination:, type:, subscribed_events:, **params)
12
- attrs = {description: description, destination: destination, type: type, subscribed_events: subscribed_events}
10
+ attrs = { description: description, destination: destination, type: type, subscribed_events: subscribed_events }
13
11
  response = Client.post_request("notification-settings", body: attrs.merge(params))
14
12
  NotificationSetting.new(response.body["data"])
15
13
  end
@@ -27,8 +25,6 @@ module Paddle
27
25
  def delete(id:)
28
26
  Client.delete_request("notification-settings/#{id}")
29
27
  end
30
-
31
28
  end
32
-
33
29
  end
34
30
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Price < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("prices", params: params)
8
6
  Collection.from_response(response, type: Price)
9
7
  end
10
8
 
11
9
  def create(product_id:, description:, amount:, currency:, **params)
12
- attrs = {product_id: product_id, description: description, unit_price: {amount: amount, currency_code: currency}}
10
+ attrs = { product_id: product_id, description: description, unit_price: { amount: amount, currency_code: currency } }
13
11
  response = Client.post_request("prices", body: attrs.merge(params))
14
12
  Price.new(response.body["data"])
15
13
  end
@@ -23,8 +21,6 @@ module Paddle
23
21
  response = Client.patch_request("prices/#{id}", body: params)
24
22
  Price.new(response.body["data"])
25
23
  end
26
-
27
24
  end
28
-
29
25
  end
30
26
  end
@@ -1,15 +1,11 @@
1
1
  module Paddle
2
2
  class PricingPreview < Object
3
-
4
3
  class << self
5
-
6
4
  def generate(items:, **params)
7
- attrs = {items: items}
5
+ attrs = { items: items }
8
6
  response = Client.post_request("pricing-preview", body: attrs.merge(params))
9
7
  PricingPreview.new(response.body["data"])
10
8
  end
11
-
12
9
  end
13
-
14
10
  end
15
11
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Product < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("products", params: params)
8
6
  Collection.from_response(response, type: Product)
9
7
  end
10
8
 
11
9
  def create(name:, tax_category:, **params)
12
- attrs = {name: name, tax_category: tax_category}
10
+ attrs = { name: name, tax_category: tax_category }
13
11
  response = Client.post_request("products", body: attrs.merge(params))
14
12
  Product.new(response.body["data"])
15
13
  end
@@ -23,8 +21,6 @@ module Paddle
23
21
  response = Client.patch_request("products/#{id}", body: params)
24
22
  Product.new(response.body["data"])
25
23
  end
26
-
27
24
  end
28
-
29
25
  end
30
26
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Report < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("reports", params: params)
8
6
  Collection.from_response(response, type: Report)
9
7
  end
10
8
 
11
9
  def create(type:, filters:, **params)
12
- attrs = {type: type, filters: filters}
10
+ attrs = { type: type, filters: filters }
13
11
  response = Client.post_request("reports", body: attrs.merge(params))
14
12
  Report.new(response.body["data"])
15
13
  end
@@ -22,11 +20,9 @@ module Paddle
22
20
  def csv(id:)
23
21
  response = Client.get_request("reports/#{id}/download-url")
24
22
  if response.success?
25
- return response.body["data"]["url"]
23
+ response.body["data"]["url"]
26
24
  end
27
25
  end
28
-
29
26
  end
30
-
31
27
  end
32
28
  end
@@ -1,15 +1,13 @@
1
1
  module Paddle
2
2
  class Subscription < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("subscriptions", params: params)
8
6
  Collection.from_response(response, type: Subscription)
9
7
  end
10
8
 
11
9
  def retrieve(id:, extra: nil)
12
- params = extra ? {include: extra} : {}
10
+ params = extra ? { include: extra } : {}
13
11
  response = Client.get_request("subscriptions/#{id}", params: params)
14
12
  Subscription.new(response.body["data"])
15
13
  end
@@ -30,7 +28,7 @@ module Paddle
30
28
  end
31
29
 
32
30
  def charge(id:, items:, effective_from:, **params)
33
- attrs = {items: items, effective_from: effective_from}
31
+ attrs = { items: items, effective_from: effective_from }
34
32
  response = Client.post_request("subscriptions/#{id}/charge", body: attrs.merge(params))
35
33
  Subscription.new(response.body["data"])
36
34
  end
@@ -41,7 +39,7 @@ module Paddle
41
39
  end
42
40
 
43
41
  def resume(id:, effective_from:, **params)
44
- attrs = {effective_from: effective_from}
42
+ attrs = { effective_from: effective_from }
45
43
  response = Client.post_request("subscriptions/#{id}/resume", body: attrs.merge(params))
46
44
  Subscription.new(response.body["data"])
47
45
  end
@@ -55,8 +53,6 @@ module Paddle
55
53
  response = Client.post_request("subscriptions/#{id}/activate")
56
54
  Subscription.new(response.body["data"])
57
55
  end
58
-
59
56
  end
60
-
61
57
  end
62
58
  end
@@ -1,21 +1,19 @@
1
1
  module Paddle
2
2
  class Transaction < Object
3
-
4
3
  class << self
5
-
6
4
  def list(**params)
7
5
  response = Client.get_request("transactions", params: params)
8
6
  Collection.from_response(response, type: Transaction)
9
7
  end
10
8
 
11
9
  def create(items:, **params)
12
- attrs = {items: items}
10
+ attrs = { items: items }
13
11
  response = Client.post_request("transactions", body: attrs.merge(params))
14
12
  Transaction.new(response.body["data"])
15
13
  end
16
14
 
17
15
  def retrieve(id:, extra: nil)
18
- params = extra ? {include: extra} : {}
16
+ params = extra ? { include: extra } : {}
19
17
  response = Client.get_request("transactions/#{id}", params: params)
20
18
  Transaction.new(response.body["data"])
21
19
  end
@@ -28,17 +26,15 @@ module Paddle
28
26
  def invoice(id:)
29
27
  response = Client.get_request("transactions/#{id}/invoice")
30
28
  if response.success?
31
- return response.body["data"]["url"]
29
+ response.body["data"]["url"]
32
30
  end
33
31
  end
34
32
 
35
33
  def preview(items:, **params)
36
- attrs = {items: items}
34
+ attrs = { items: items }
37
35
  response = Client.post_request("transactions/preview", body: attrs.merge(params))
38
36
  Transaction.new(response.body["data"])
39
37
  end
40
-
41
38
  end
42
-
43
39
  end
44
40
  end
data/lib/paddle/object.rb CHANGED
@@ -8,12 +8,33 @@ module Paddle
8
8
 
9
9
  def to_ostruct(obj)
10
10
  if obj.is_a?(Hash)
11
- OpenStruct.new(obj.map { |key, val| [key, to_ostruct(val)] }.to_h)
11
+ OpenStruct.new(obj.map { |key, val| [ key, to_ostruct(val) ] }.to_h)
12
12
  elsif obj.is_a?(Array)
13
13
  obj.map { |o| to_ostruct(o) }
14
14
  else # Assumed to be a primitive value
15
15
  obj
16
16
  end
17
17
  end
18
+
19
+ def update(**params)
20
+ method_missing :update unless klass.respond_to? :update
21
+
22
+ primary_attributes = klass.method(:update).parameters.select { |(type, name)| type == :keyreq }.map(&:last) # Identified by whatever is a required named parameter.
23
+
24
+ primary_attributes.each do |attrib|
25
+ # ? Should we need to handle blank strings here?
26
+ params[attrib] = self[attrib] || self["#{attrib}_id"] # Handling for customer (customer_id) and id.
27
+ end
28
+
29
+ klass.public_send(:update, **params).each_pair { |key, val| self[key] = val } # Updating self
30
+
31
+ self
32
+ end
33
+
34
+ private
35
+
36
+ def klass
37
+ self.class
38
+ end
18
39
  end
19
40
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paddle
4
- VERSION = "2.2.0"
4
+ VERSION = "2.3.0"
5
5
  end
data/lib/paddle.rb CHANGED
@@ -5,11 +5,12 @@ require "faraday"
5
5
  require_relative "paddle/version"
6
6
 
7
7
  module Paddle
8
-
9
8
  autoload :Configuration, "paddle/configuration"
10
9
  autoload :Client, "paddle/client"
11
10
  autoload :Collection, "paddle/collection"
12
11
  autoload :Error, "paddle/error"
12
+ autoload :ErrorFactory, "paddle/error"
13
+
13
14
  autoload :Object, "paddle/object"
14
15
 
15
16
  class << self
@@ -75,5 +76,4 @@ module Paddle
75
76
  autoload :Modifier, "paddle/classic/objects/modifier"
76
77
  autoload :Charge, "paddle/classic/objects/charge"
77
78
  end
78
-
79
79
  end
data/paddle.gemspec CHANGED
@@ -5,8 +5,8 @@ require_relative "lib/paddle/version"
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "paddle"
7
7
  spec.version = Paddle::VERSION
8
- spec.authors = ["Dean Perry"]
9
- spec.email = ["dean@deanpcmad.com"]
8
+ spec.authors = [ "Dean Perry" ]
9
+ spec.email = [ "dean@deanpcmad.com" ]
10
10
 
11
11
  spec.summary = "Ruby library for the Paddle Billing & Classic APIs"
12
12
  spec.homepage = "https://github.com/deanpcmad/paddle"
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  end
25
25
  spec.bindir = "exe"
26
26
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
- spec.require_paths = ["lib"]
27
+ spec.require_paths = [ "lib" ]
28
28
 
29
29
  spec.add_dependency "faraday", "~> 2.0"
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Perry
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-24 00:00:00.000000000 Z
11
+ date: 2024-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- description:
27
+ description:
28
28
  email:
29
29
  - dean@deanpcmad.com
30
30
  executables: []
@@ -32,6 +32,7 @@ extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
34
  - ".env.example"
35
+ - ".rubocop.yml"
35
36
  - Gemfile
36
37
  - Gemfile.lock
37
38
  - README.md
@@ -94,7 +95,7 @@ licenses: []
94
95
  metadata:
95
96
  homepage_uri: https://github.com/deanpcmad/paddle
96
97
  source_code_uri: https://github.com/deanpcmad/paddle
97
- post_install_message:
98
+ post_install_message:
98
99
  rdoc_options: []
99
100
  require_paths:
100
101
  - lib
@@ -109,8 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
110
  - !ruby/object:Gem::Version
110
111
  version: '0'
111
112
  requirements: []
112
- rubygems_version: 3.5.9
113
- signing_key:
113
+ rubygems_version: 3.5.15
114
+ signing_key:
114
115
  specification_version: 4
115
116
  summary: Ruby library for the Paddle Billing & Classic APIs
116
117
  test_files: []