paddle 2.2.0 → 2.3.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.
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: []