payload-api 0.5.0 → 0.6.1

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
  SHA256:
3
- metadata.gz: 66c7eb5c0125eb3e66a5800851c6e66e42ae36138a2b89516b2ae8a823cacc7d
4
- data.tar.gz: 602f23d391904acdb9ddf3540990692f8f54284746d3bba5eb528827f2f802da
3
+ metadata.gz: a6364ada87b188e97370c985aaee315c1abe7149162d0bfe1a1feca21407e416
4
+ data.tar.gz: 0ba29b0d267e6dbe078c0ffe8a20ac915cfebb515e9ac20f6d7f8697160a45d5
5
5
  SHA512:
6
- metadata.gz: 19b0346676cab8cbd11a997fbb30f2a9ccec35eb16bfe7905da763efc6f5b7efc27002ac828ff0b14041e284bdd10d0cbc093dbb3d09350dd08bb5cd82bfa1af
7
- data.tar.gz: 7abac9292dcc52fe334f4182f59d6c4253242451a5f3e4aec7997399a6469c56caadf3862b511529d08b5e65c5779764ad868b2e06134266500deedbfa0e73f4
6
+ metadata.gz: d6e5b2ebca0650bc0358a0d8883681363a519795ffa49349fb936f821175d9d173f45ad49c86553ac701f3a284bfd48f8cdf901831fa7b559a7dc13c0f0adb07
7
+ data.tar.gz: 18634323e7c0221562430f79fc68638f2db08f2ee9caea5bb2b3c7b3f577aa2d8b70627ad17af9e3b72d2f9ed802ef211b69a2bc60566036b8922f3bb2b35b5b
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2024 Payload (http://payload.com)
3
+ Copyright (c) 2026 Payload (http://payload.com)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Payload
4
+ class ARMFilter
5
+ attr_reader :attr, :opval, :val
6
+
7
+ def initialize(attr, val)
8
+ @attr = attr.to_s
9
+ @val = val
10
+ @opval = self.class.op + val.to_s
11
+ end
12
+
13
+ def self.op
14
+ ''
15
+ end
16
+
17
+ def |(other)
18
+ raise TypeError, 'invalid type' unless other.is_a?(Payload::ARMFilter)
19
+ raise ArgumentError, '`or` only works on the same attribute' if other.attr != @attr
20
+ joined = [@opval, other.opval].join('|')
21
+ Payload::ARMEqual.new(@attr, joined)
22
+ end
23
+ end
24
+
25
+ class ARMEqual < ARMFilter
26
+ def self.op
27
+ ''
28
+ end
29
+ end
30
+
31
+ class ARMNotEqual < ARMFilter
32
+ def self.op
33
+ '!'
34
+ end
35
+ end
36
+
37
+ class ARMGreaterThan < ARMFilter
38
+ def self.op
39
+ '>'
40
+ end
41
+ end
42
+
43
+ class ARMLessThan < ARMFilter
44
+ def self.op
45
+ '<'
46
+ end
47
+ end
48
+
49
+ class ARMGreaterThanEqual < ARMFilter
50
+ def self.op
51
+ '>='
52
+ end
53
+ end
54
+
55
+ class ARMLessThanEqual < ARMFilter
56
+ def self.op
57
+ '<='
58
+ end
59
+ end
60
+
61
+ class ARMContains < ARMFilter
62
+ def self.op
63
+ '?*'
64
+ end
65
+ end
66
+
67
+ # Root proxy for pl.attr so that pl.attr.name returns an Attr (not Class#name).
68
+ # Session#attr returns this instead of the Attr class to avoid Class/Module methods (e.g. .name) shadowing attribute names.
69
+ class AttrRoot
70
+ def method_missing(name, *args)
71
+ if args.size == 1 && args[0].is_a?(Symbol)
72
+ inner = Attr.new(name.to_s)
73
+ Attr.new(args[0].to_s, inner).call
74
+ else
75
+ Attr.new(name.to_s)
76
+ end
77
+ end
78
+
79
+ def respond_to_missing?(name, include_private = false)
80
+ true
81
+ end
82
+ end
83
+
84
+ # Attribute DSL for select/group_by/order_by and filter expressions.
85
+ # - pl.attr.id -> "id"
86
+ # - pl.attr.created_at(:month) -> "month(created_at)"
87
+ # - pl.attr.amount(:sum) -> "sum(amount)"
88
+ # - pl.attr.sender.account_id -> "sender[account_id]"
89
+ class Attr
90
+ attr_reader :param, :parent
91
+
92
+ class << self
93
+ def method_missing(name, *args)
94
+ new(name.to_s)
95
+ end
96
+
97
+ def respond_to_missing?(name, include_private = false)
98
+ true
99
+ end
100
+ end
101
+
102
+ def initialize(param, parent = nil)
103
+ @param = param.to_s
104
+ @parent = parent
105
+ @is_method = false
106
+ end
107
+
108
+ def key
109
+ @parent ? "#{@parent.key}[#{@param}]" : @param
110
+ end
111
+
112
+ def to_s
113
+ @is_method ? "#{@param}(#{@parent.key})" : key
114
+ end
115
+
116
+ def strip
117
+ to_s.strip
118
+ end
119
+
120
+ def method_missing(name, *args)
121
+ raise "cannot get attr of method" if @is_method
122
+
123
+ if args.size == 1 && args[0].is_a?(Symbol)
124
+ inner = Attr.new(name.to_s, self)
125
+ Attr.new(args[0].to_s, inner).call
126
+ else
127
+ Attr.new(name.to_s, self)
128
+ end
129
+ end
130
+
131
+ def respond_to_missing?(name, include_private = false)
132
+ true
133
+ end
134
+
135
+ # Mark attribute as a function call (e.g. .month(), .sum())
136
+ def call
137
+ @is_method = true
138
+ self
139
+ end
140
+
141
+ def ==(other)
142
+ ARMEqual.new(self, other)
143
+ end
144
+
145
+ def !=(other)
146
+ ARMNotEqual.new(self, other)
147
+ end
148
+
149
+ def >(other)
150
+ ARMGreaterThan.new(self, other)
151
+ end
152
+
153
+ def <(other)
154
+ ARMLessThan.new(self, other)
155
+ end
156
+
157
+ def >=(other)
158
+ ARMGreaterThanEqual.new(self, other)
159
+ end
160
+
161
+ def <=(other)
162
+ ARMLessThanEqual.new(self, other)
163
+ end
164
+
165
+ def contains(other)
166
+ ARMContains.new(self, other)
167
+ end
168
+ end
169
+ end
@@ -29,11 +29,26 @@ module Payload
29
29
  def get(id)
30
30
  return @cls.get(id, :session => @session)
31
31
  end
32
-
32
+
33
33
  def select(*args, **data)
34
34
  @cls.select(*args, **data, session: @session)
35
35
  end
36
36
 
37
+ def order_by(*args, **data)
38
+ @cls.order_by(*args, **data, session: @session)
39
+ end
40
+
41
+ def limit(n, **data)
42
+ @cls.limit(n, **data, session: @session)
43
+ end
44
+
45
+ def offset(n, **data)
46
+ @cls.offset(n, **data, session: @session)
47
+ end
48
+
49
+ def group_by(*args, **data)
50
+ @cls.group_by(*args, **data, session: @session)
51
+ end
37
52
  end
38
53
 
39
54
  class ARMObject
@@ -103,7 +118,7 @@ module Payload
103
118
  end
104
119
 
105
120
  def [](key)
106
- return @data[key]
121
+ return @data[key.to_s]
107
122
  end
108
123
 
109
124
  def _get_request()
@@ -118,6 +133,22 @@ module Payload
118
133
  return self._get_request().select(*args, **data)
119
134
  end
120
135
 
136
+ def self.order_by(*args, **data)
137
+ self._get_request().order_by(*args, **data)
138
+ end
139
+
140
+ def self.limit(n, **data)
141
+ self._get_request().limit(n)
142
+ end
143
+
144
+ def self.offset(n, **data)
145
+ self._get_request().offset(n)
146
+ end
147
+
148
+ def self.group_by(*args, **data)
149
+ self._get_request().group_by(*args, **data)
150
+ end
151
+
121
152
  def self.filter_by(*args, **data)
122
153
  session = data[:session]
123
154
  data.delete(:session)
@@ -154,6 +185,10 @@ module Payload
154
185
  return _get_request()._request('Delete', id: self.id)
155
186
  end
156
187
 
188
+ def json
189
+ to_json
190
+ end
191
+
157
192
  def to_json(*args)
158
193
  serialized = {}
159
194
  if self.class.poly
@@ -1,5 +1,6 @@
1
1
  require "payload/exceptions"
2
2
  require "payload/utils"
3
+ require "payload/arm/attr"
3
4
  require "net/http"
4
5
  require "uri"
5
6
  require "json"
@@ -12,21 +13,46 @@ module Payload
12
13
  @cls = cls
13
14
  @session = session || Payload::Session.new(Payload::api_key, Payload::api_url)
14
15
  @filters = {}
16
+ @group_by = []
17
+ @order_by = []
18
+ @limit = nil
19
+ @offset = nil
20
+ @filter_objects = []
15
21
  end
16
22
 
17
23
  def select(*args, **data)
18
- @filters['fields'] = args.map {|a| a.strip }.join(',')
19
-
24
+ @filters['fields'] = args.map { |a| a.strip }.join(',')
20
25
  return self
21
26
  end
22
27
 
28
+ def group_by(*args, **data)
29
+ @group_by.concat(args)
30
+ self
31
+ end
32
+
33
+ def order_by(*args, **data)
34
+ @order_by.concat(args)
35
+ self
36
+ end
37
+
38
+ def limit(n)
39
+ @limit = n
40
+ self
41
+ end
42
+
43
+ def offset(n)
44
+ @offset = n
45
+ self
46
+ end
47
+
23
48
  def filter_by(*args, **data)
49
+ args.each do |f|
50
+ @filter_objects << f if f.respond_to?(:attr) && f.respond_to?(:opval)
51
+ end
24
52
  if !@cls.nil? && @cls.poly
25
53
  data = data.merge(@cls.poly)
26
54
  end
27
-
28
55
  @filters = @filters.merge(data)
29
-
30
56
  return self
31
57
  end
32
58
 
@@ -35,6 +61,17 @@ module Payload
35
61
  return self._request('Get')
36
62
  end
37
63
 
64
+ def [](key)
65
+ case key
66
+ when Range
67
+ raise ArgumentError, 'Negative slice indices not supported' if key.begin && key.begin < 0
68
+ raise ArgumentError, 'Negative slice indices not supported' if key.end && key.end < 0
69
+ offset(key.begin).limit(key.size).all()
70
+ else
71
+ raise TypeError, "invalid key or index: #{key.inspect}"
72
+ end
73
+ end
74
+
38
75
  def get(id)
39
76
  if id.nil? || id.empty?
40
77
  throw 'id cannot be empty'
@@ -127,17 +164,29 @@ module Payload
127
164
  http.request(request)
128
165
  end
129
166
 
167
+ def request_params
168
+ params = @filters.dup
169
+ @filter_objects.each { |f| params[f.attr] = f.opval }
170
+ @group_by.each_with_index { |v, i| params["group_by[#{i}]"] = v.to_s }
171
+ @order_by.each_with_index { |v, i| params["order_by[#{i}]"] = v.to_s }
172
+ params['limit'] = @limit.to_s if @limit
173
+ params['offset'] = @offset.to_s if @offset
174
+ params
175
+ end
176
+
130
177
  def _request(method, id: nil, json: nil)
131
178
  if !@cls.nil?
132
179
  if @cls.spec.key?("endpoint")
133
180
  endpoint = @cls.spec["endpoint"]
134
181
  else
135
- endpoint = "/"+@cls.spec["object"]+"s"
182
+ obj = @cls.spec["object"]
183
+ endpoint = "/" + (obj.end_with?("s") ? obj : obj + "s")
136
184
  end
137
185
  else
138
186
  if json.is_a? Array
139
187
  if json.all? {|obj| obj.key?("object") }
140
- endpoint = json[0]["object"]+"s"
188
+ obj = json[0]["object"]
189
+ endpoint = (obj.end_with?("s") ? obj : obj + "s")
141
190
  end
142
191
  end
143
192
  end
@@ -146,8 +195,9 @@ module Payload
146
195
  endpoint = File.join(endpoint, id)
147
196
  end
148
197
 
198
+ params = request_params
149
199
  url = URI.join(@session.api_url, endpoint)
150
- url.query = URI.encode_www_form(@filters)
200
+ url.query = URI.encode_www_form(params)
151
201
 
152
202
  http = Net::HTTP.new(url.host, url.port)
153
203
 
@@ -1,15 +1,15 @@
1
1
  require 'payload/arm/request'
2
-
2
+ require 'payload/arm/attr'
3
3
 
4
4
  module Payload
5
5
  class Session
6
6
  attr_accessor :api_key, :api_url, :api_version
7
-
7
+
8
8
  def initialize(api_key = nil, api_url = nil, api_version = nil, **kwargs)
9
9
  @api_key = kwargs[:api_key] || api_key
10
10
  @api_url = kwargs[:api_url] || api_url || Payload.URL
11
11
  @api_version = kwargs[:api_version] || api_version || Payload.api_version
12
-
12
+
13
13
  Payload.constants.each do |c|
14
14
  val = Payload.const_get(c)
15
15
  if val.is_a?(Class) && val < Payload::ARMObject
@@ -17,11 +17,15 @@ module Payload
17
17
  end
18
18
  end
19
19
  end
20
-
20
+
21
21
  def _get_request(cls = nil)
22
22
  return Payload::ARMRequest.new(cls, self)
23
23
  end
24
24
 
25
+ def attr
26
+ Payload::AttrRoot.new
27
+ end
28
+
25
29
  def query(cls)
26
30
  return self._get_request(cls)
27
31
  end
@@ -18,6 +18,21 @@ module Payload
18
18
  @code='400'
19
19
  end
20
20
 
21
+ class TransactionDeclined < BadRequest
22
+ attr_reader :transaction
23
+
24
+ def initialize(msg, data = nil)
25
+ super(msg, data)
26
+ @transaction = if data && data['details'].is_a?(Hash)
27
+ cls = Payload.get_cls(data['details'])
28
+ cls = Payload::Transaction if cls.nil?
29
+ cls.new(data['details'], nil)
30
+ else
31
+ nil
32
+ end
33
+ end
34
+ end
35
+
21
36
  class InvalidAttributes < PayloadError
22
37
  @code='400'
23
38
  end
@@ -62,10 +62,18 @@ module Payload
62
62
  @spec = { 'object' => 'invoice' }
63
63
  end
64
64
 
65
+ class InvoiceAttachment < ARMObject
66
+ @spec = { 'object' => 'invoice_attachment' }
67
+ end
68
+
65
69
  class PaymentActivation < ARMObject
66
70
  @spec = { 'object' => 'payment_activation' }
67
71
  end
68
72
 
73
+ class ProcessingSettings < ARMObject
74
+ @spec = { 'object' => 'processing_settings' }
75
+ end
76
+
69
77
  class Webhook < ARMObject
70
78
  @spec = { 'object' => 'webhook' }
71
79
  end
@@ -96,7 +104,7 @@ module Payload
96
104
  class ProcessingAccount < ARMObject
97
105
  @spec = { 'object' => 'processing_account' }
98
106
  end
99
-
107
+
100
108
  class Org < ARMObject
101
109
  @spec = { 'object' => 'org', 'endpoint' => '/account/orgs' }
102
110
  end
@@ -123,7 +131,7 @@ module Payload
123
131
  end
124
132
 
125
133
  class Entity < ARMObject
126
- @spec = { 'object' => 'entity' }
134
+ @spec = { 'object' => 'entity', 'endpoint' => 'entities' }
127
135
  end
128
136
 
129
137
  class Stakeholder < ARMObject
@@ -1,3 +1,3 @@
1
1
  module Payload
2
- VERSION = '0.5.0'
3
- end
2
+ VERSION = '0.6.1'
3
+ end