pennylane 0.2.0.pre.alpha → 1.0.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 +4 -4
- data/CHANGELOG.md +14 -1
- data/Gemfile.lock +1 -1
- data/README.md +159 -6
- data/lib/pennylane/client.rb +7 -6
- data/lib/pennylane/list_object.rb +1 -1
- data/lib/pennylane/object.rb +1 -3
- data/lib/pennylane/object_types.rb +15 -0
- data/lib/pennylane/resources/base.rb +14 -7
- data/lib/pennylane/resources/customer_invoice.rb +52 -7
- data/lib/pennylane/util.rb +6 -1
- data/lib/pennylane/version.rb +1 -1
- data/lib/pennylane.rb +2 -11
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d39d39c57d464e5c95acf6535e0e80508e9836fcbd8dd3afe49373283d965438
|
|
4
|
+
data.tar.gz: f4339e0fda690f67625aefb006f3964fdeefd8f125d9ff68ef26408cbb30caef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 745d583286f8eeb20da9acb324ae2b7b0e2ca9611537c4aa340d674ad8c380428ee337e03c70c823940e61748520c7b5a267fa09a34493af4a6234a7ebded501
|
|
7
|
+
data.tar.gz: 4e671e89e28b95717eb5a800c4463896349eadf5756a1ebb11a69a645391881bb51f247960d9f6bd6e118a3386542796cf6646defaf7baafaa36a4d6152a8fc3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
## [
|
|
1
|
+
## [1.0.1] - 2024-04-29
|
|
2
|
+
- Fixed gem initialization issue (resources/*.rb) from a Rails app.
|
|
3
|
+
|
|
4
|
+
## [1.0.0] - 2024-04-29
|
|
5
|
+
|
|
6
|
+
- Support CustomerInvoice:
|
|
7
|
+
- `finalize`
|
|
8
|
+
- `mark_as_paid`
|
|
9
|
+
- `send_by_email`
|
|
10
|
+
- `links`
|
|
11
|
+
- `import`
|
|
12
|
+
- Support per request `api_key` e.g `Pennylane::Customer.retrieve('cus_id', {api_key: 'x0fd....'})`
|
|
13
|
+
- Endpoints returning empty response we are doing +1 GET request at the resource. Not the best solution but at least we are sure we have fresh data.
|
|
14
|
+
- Added resource properties access with `#[]` e.g `cus['name']`
|
|
2
15
|
|
|
3
16
|
## [0.2.0-alpha] - 2024-04-20
|
|
4
17
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -16,9 +16,22 @@ Install the gem and add to the application's Gemfile by executing:
|
|
|
16
16
|
$ bundle add pennylane
|
|
17
17
|
|
|
18
18
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
19
|
+
```ruby
|
|
20
|
+
# Add to gemfile
|
|
21
|
+
gem 'pennylane'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
For Rails app :
|
|
25
|
+
```ruby
|
|
26
|
+
# Create initializers/pennylane.rb
|
|
27
|
+
Pennylane.api_key = Rails.application.credentials.dig(:pennylane, :api_key)
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
# Add credentials to config/credentials.yml.enc
|
|
30
|
+
$ EDITOR=vim bin/rails credentials:edit
|
|
21
31
|
|
|
32
|
+
pennylane:
|
|
33
|
+
api_key: 'x0fd....'
|
|
34
|
+
```
|
|
22
35
|
## Requirements
|
|
23
36
|
Ruby 2.3+.
|
|
24
37
|
|
|
@@ -32,7 +45,11 @@ Pennylane.api_key = 'x0fd....'
|
|
|
32
45
|
|
|
33
46
|
# list customers
|
|
34
47
|
Pennylane::Customer.list
|
|
48
|
+
```
|
|
35
49
|
|
|
50
|
+
### Customers ([API Doc](https://pennylane.readme.io/reference/customers-post-1))
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
36
53
|
# filter and paginate customers
|
|
37
54
|
Pennylane::Customer.list(filter: [{field: 'name', operator: 'eq', value: 'Apple'}], page: 2)
|
|
38
55
|
|
|
@@ -43,9 +60,131 @@ Pennylane::Customer.retrieve('38a1f19a-256d-4692-a8fe-0a16403f59ff')
|
|
|
43
60
|
cus = Pennylane::Customer.retrieve('38a1f19a-256d-4692-a8fe-0a16403f59ff')
|
|
44
61
|
cus.update(name: 'Apple Inc')
|
|
45
62
|
|
|
63
|
+
# Create a customer
|
|
64
|
+
Pennylane::Customer.create customer_type: 'company', name: 'Tesla', address: '4 rue du faubourg', postal_code: '75008', city: 'Paris', country_alpha2: 'FR'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### CustomerInvoices ([API Doc](https://pennylane.readme.io/reference/customer_invoices-import-1))
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
# Create a customer invoice
|
|
71
|
+
Pennylane::CustomerInvoice.create(
|
|
72
|
+
create_customer: true,
|
|
73
|
+
create_products: true,
|
|
74
|
+
invoice: {
|
|
75
|
+
date: '2021-01-01',
|
|
76
|
+
deadline: '2021-01-31',
|
|
77
|
+
customer: {
|
|
78
|
+
name: 'Tesla',
|
|
79
|
+
customer_type: 'company',
|
|
80
|
+
address: '4 rue du faubourg',
|
|
81
|
+
postal_code: '75001',
|
|
82
|
+
city: 'Paris',
|
|
83
|
+
country_alpha2: 'FR',
|
|
84
|
+
emails: ['stephane@tesla.com'] },
|
|
85
|
+
line_items: [
|
|
86
|
+
{
|
|
87
|
+
description: 'Consulting',
|
|
88
|
+
quantity: 1,
|
|
89
|
+
unit_price: 1000
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# List customer invoices
|
|
96
|
+
Pennylane::CustomerInvoice.list
|
|
97
|
+
|
|
98
|
+
# Retrieve a customer invoice
|
|
99
|
+
invoice = Pennylane::CustomerInvoice.retrieve('38a1f19a-256d-4692-a8fe-0a16403f59ff')
|
|
100
|
+
|
|
101
|
+
# Finalize a customer invoice
|
|
102
|
+
invoice.finalize
|
|
103
|
+
|
|
104
|
+
# Send a customer invoice
|
|
105
|
+
invoice.send_by_email
|
|
106
|
+
|
|
107
|
+
# Mark a customer invoice as paid
|
|
108
|
+
invoice.mark_as_paid
|
|
109
|
+
|
|
110
|
+
# Link an invoice and a credit note
|
|
111
|
+
credit_note = Pennylane::CustomerInvoice.retrieve('some-credit-note-id')
|
|
112
|
+
Pennylane::CustomerInvoice.links(invoice.quote_group_uuid, credit_note.quote_group_uuid)
|
|
113
|
+
|
|
114
|
+
# Import a customer invoice
|
|
115
|
+
Pennylane::CustomerInvoice.import(file: Util.file(File.expand_path('../fixtures/files/invoice.pdf', __FILE__)),
|
|
116
|
+
create_customer: true,
|
|
117
|
+
invoice: { date: Date.today, deadline: Date.today >> 1,
|
|
118
|
+
customer: {
|
|
119
|
+
name: 'Tesla',
|
|
120
|
+
customer_type: 'company',
|
|
121
|
+
address: '4 rue du faubourg',
|
|
122
|
+
postal_code: '75001',
|
|
123
|
+
city: 'Paris',
|
|
124
|
+
country_alpha2: 'FR',
|
|
125
|
+
emails: ['stephane@tesla.com'] },
|
|
126
|
+
line_items: [
|
|
127
|
+
{
|
|
128
|
+
description: 'Consulting',
|
|
129
|
+
quantity: 1,
|
|
130
|
+
unit_price: 1000
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
### Suppliers ([API Doc](https://pennylane.readme.io/reference/suppliers-post))
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
# Create a supplier
|
|
140
|
+
Pennylane::Supplier.create(name: 'Apple Inc', address: '4 rue du faubourg', postal_code: '75008', city: 'Paris', country_alpha2: 'FR')
|
|
141
|
+
|
|
142
|
+
# Retrieve a supplier
|
|
143
|
+
Pennylane::Supplier.retrieve('supplier_id')
|
|
144
|
+
|
|
145
|
+
# List all suppliers
|
|
146
|
+
Pennylane::Supplier.list
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Products ([API Doc](https://pennylane.readme.io/reference/products-post-1))
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
# Create a product
|
|
153
|
+
Pennylane::Product.create(label: 'Macbook Pro', unit: 'piece', price: 2_999, vat_rate: 'FR_200', currency: 'EUR')
|
|
154
|
+
|
|
155
|
+
# List all products
|
|
156
|
+
Pennylane::Product.list
|
|
157
|
+
|
|
158
|
+
# Retrieve a product
|
|
159
|
+
product = Pennylane::Product.retrieve('product_id')
|
|
160
|
+
|
|
161
|
+
# Update a product
|
|
162
|
+
product.update(label: 'Macbook Pro 2021')
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Categories ([API Doc](https://pennylane.readme.io/reference/tags-get))
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
# Create a category
|
|
169
|
+
Pennylane::Category.create(name: 'IT')
|
|
170
|
+
|
|
171
|
+
# Retrieve a category
|
|
172
|
+
Pennylane::Category.retrieve('category_id')
|
|
173
|
+
|
|
174
|
+
# List all categories
|
|
175
|
+
Pennylane::Category.list
|
|
176
|
+
|
|
177
|
+
# Update a category
|
|
178
|
+
category = Pennylane::Category.retrieve('category_id')
|
|
179
|
+
category.update(name: 'IT Services')
|
|
180
|
+
```
|
|
181
|
+
### CategoryGroups ([API Doc](https://pennylane.readme.io/reference/tag-groups-get))
|
|
182
|
+
```ruby
|
|
183
|
+
# List all category groups
|
|
184
|
+
Pennylane::CategoryGroup.list
|
|
46
185
|
```
|
|
47
186
|
|
|
48
|
-
### Per-request api key
|
|
187
|
+
### Per-request api key
|
|
49
188
|
For apps that need to use multiple keys during the lifetime of a process. it's also possible to set a per-request key:
|
|
50
189
|
```ruby
|
|
51
190
|
require "pennylane"
|
|
@@ -64,6 +203,19 @@ Pennylane::Customer.retrieve(
|
|
|
64
203
|
}
|
|
65
204
|
)
|
|
66
205
|
|
|
206
|
+
```
|
|
207
|
+
### Accessing resource properties
|
|
208
|
+
|
|
209
|
+
Both indexer and accessors can be used to retrieve values of resource properties.
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
customer = Pennylane::Customer.retrieve('customer_id')
|
|
213
|
+
puts customer['name']
|
|
214
|
+
puts customer.name
|
|
215
|
+
|
|
216
|
+
# NOTE: To do this the gem will try to guess the key of the resource.
|
|
217
|
+
# Otherwise we will have to do Pennylane::Customer.retrieve('customer_id').customer.name
|
|
218
|
+
# We rely on `method_missing` to do Pennylane::Customer.retrieve('customer_id').name
|
|
67
219
|
```
|
|
68
220
|
|
|
69
221
|
## Test mode
|
|
@@ -72,14 +224,15 @@ Pennylane provide a [test environment](https://help.pennylane.com/fr/articles/18
|
|
|
72
224
|
|
|
73
225
|
## Development
|
|
74
226
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
227
|
+
```bash
|
|
228
|
+
bundle install
|
|
229
|
+
bundle exec rake test
|
|
230
|
+
```
|
|
78
231
|
|
|
79
232
|
Resources implemented so far :
|
|
80
233
|
### CUSTOMER INVOICING
|
|
81
234
|
|
|
82
|
-
- Customer Invoices
|
|
235
|
+
- Customer Invoices ✅
|
|
83
236
|
- Estimates 🚧
|
|
84
237
|
- Billing Subscriptions 🚧
|
|
85
238
|
|
data/lib/pennylane/client.rb
CHANGED
|
@@ -3,7 +3,7 @@ module Pennylane
|
|
|
3
3
|
BASE_URI = 'app.pennylane.com/api/external'.freeze
|
|
4
4
|
VERSION = 'v1'.freeze
|
|
5
5
|
|
|
6
|
-
attr_accessor :
|
|
6
|
+
attr_accessor :version
|
|
7
7
|
|
|
8
8
|
def initialize(key, version: 'v1')
|
|
9
9
|
@key = key
|
|
@@ -21,7 +21,7 @@ module Pennylane
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def authorization
|
|
24
|
+
def authorization(key)
|
|
25
25
|
"Bearer #{key}"
|
|
26
26
|
end
|
|
27
27
|
def http
|
|
@@ -34,8 +34,8 @@ module Pennylane
|
|
|
34
34
|
Net::HTTP.const_get(method.to_s.capitalize)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
def request method, path, params
|
|
38
|
-
req = initialize_request(method, path, params[:query]).tap do |req|
|
|
37
|
+
def request method, path, params: {}, opts: {}
|
|
38
|
+
req = initialize_request(method, path, params[:query], opts).tap do |req|
|
|
39
39
|
req.body = params[:body].to_json if params[:body]
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -61,10 +61,11 @@ module Pennylane
|
|
|
61
61
|
def should_handle_as_error?(code)
|
|
62
62
|
code.to_i >= 400
|
|
63
63
|
end
|
|
64
|
-
|
|
64
|
+
|
|
65
|
+
def initialize_request method=nil, path=nil, params={}, opts={}
|
|
65
66
|
klass(method).new(url(path, params)).tap do |request|
|
|
66
67
|
request["content-type"] = 'application/json'
|
|
67
|
-
request["authorization"] = authorization
|
|
68
|
+
request["authorization"] = authorization(opts.fetch(:api_key, @key))
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
|
|
@@ -19,7 +19,7 @@ module Pennylane
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def key_for(resp)
|
|
22
|
-
resp.keys.find { |k| Pennylane::
|
|
22
|
+
resp.keys.find { |k| Pennylane::ObjectTypes.object_names_to_classes.keys.include?(Util.singularize(k.to_s)) } || resp.keys.find { |k| resp[k].is_a? Array }
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
end
|
data/lib/pennylane/object.rb
CHANGED
|
@@ -86,9 +86,7 @@ module Pennylane
|
|
|
86
86
|
when Pennylane::Object
|
|
87
87
|
obj.class.build_from(
|
|
88
88
|
deep_copy(obj.instance_variable_get(:@values)),
|
|
89
|
-
obj.instance_variable_get(:@opts)
|
|
90
|
-
Util::OPTS_COPYABLE.include?(k)
|
|
91
|
-
end
|
|
89
|
+
obj.instance_variable_get(:@opts)
|
|
92
90
|
)
|
|
93
91
|
else
|
|
94
92
|
obj
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Pennylane
|
|
2
|
+
module ObjectTypes
|
|
3
|
+
def self.object_names_to_classes
|
|
4
|
+
{
|
|
5
|
+
ListObject.object_name => ListObject,
|
|
6
|
+
Category.object_name => Category,
|
|
7
|
+
CategoryGroup.object_name => CategoryGroup,
|
|
8
|
+
Customer.object_name => Customer,
|
|
9
|
+
CustomerInvoice.object_name => CustomerInvoice,
|
|
10
|
+
Product.object_name => Product,
|
|
11
|
+
Supplier.object_name => Supplier
|
|
12
|
+
}.freeze
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module Pennylane
|
|
2
2
|
module Resources
|
|
3
3
|
class Base < Pennylane::Object
|
|
4
|
+
|
|
4
5
|
class << self
|
|
5
6
|
|
|
6
7
|
def object_name
|
|
@@ -13,25 +14,26 @@ module Pennylane
|
|
|
13
14
|
|
|
14
15
|
def request_pennylane_object(method:, path:, params: {}, opts: {}, usage: [], with: {})
|
|
15
16
|
resp, opts = execute_resource_request(method, path, params, opts, usage)
|
|
16
|
-
|
|
17
|
+
if resp.empty?
|
|
18
|
+
{}
|
|
19
|
+
else
|
|
20
|
+
Util.convert_to_pennylane_object(Util.normalize_response(resp, with), params, opts)
|
|
21
|
+
end
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
def execute_resource_request(method, path, params = {}, opts = {}, usage = [])
|
|
20
|
-
api_key = opts.delete(:api_key) || Pennylane.api_key
|
|
21
|
-
|
|
22
|
-
|
|
23
25
|
resp = client.request(
|
|
24
26
|
method,
|
|
25
27
|
path,
|
|
26
28
|
params: params,
|
|
27
29
|
opts: opts
|
|
28
30
|
)
|
|
29
|
-
|
|
30
|
-
[JSON.parse(resp.read_body), opts]
|
|
31
|
+
[JSON.parse(resp.read_body || "{}"), opts] # in case body is nil ew return an empty hash
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
def client
|
|
34
|
-
@client ||=
|
|
35
|
+
@client ||= {}
|
|
36
|
+
@client[Pennylane.api_key] ||= Pennylane::Client.new(Pennylane.api_key)
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def normalize_filters(filters)
|
|
@@ -47,6 +49,11 @@ module Pennylane
|
|
|
47
49
|
super
|
|
48
50
|
end
|
|
49
51
|
|
|
52
|
+
# object happens to be nil when the object is the nested object
|
|
53
|
+
def [](k)
|
|
54
|
+
(object && object[k.to_sym]) || @values[k.to_sym]
|
|
55
|
+
end
|
|
56
|
+
|
|
50
57
|
#
|
|
51
58
|
def object
|
|
52
59
|
@values[self.class.object_name.to_sym]
|
|
@@ -20,26 +20,71 @@ module Pennylane
|
|
|
20
20
|
request_pennylane_object(method: :post, path: "/customer_invoices", params: { body: params }, opts: opts, with: { invoice: 'customer_invoice' })
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def import params, opts={}
|
|
24
|
+
request_pennylane_object(method: :post, path: "/customer_invoices/import", params: { body: params }, opts: opts, with: { invoice: 'customer_invoice' })
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def links(*quote_group_uuids, opts: {})
|
|
28
|
+
request_pennylane_object(method: :post, path: "/customer_invoices/links", params: { body: { quote_group_uuids: quote_group_uuids } },
|
|
29
|
+
opts: {})
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# since object name is different from the class name, we need to override the object_name method
|
|
34
|
+
def object
|
|
35
|
+
@values[:invoice]
|
|
23
36
|
end
|
|
24
37
|
|
|
38
|
+
# doesnt have a `source_id` so we override it
|
|
39
|
+
def id
|
|
40
|
+
object.id
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# API CALLS
|
|
44
|
+
|
|
25
45
|
# since object name is different from the class name, we need to override the method
|
|
26
46
|
def update(attributes)
|
|
27
|
-
resp, opts = self.class.request_pennylane_object(method: :put,
|
|
47
|
+
resp, opts = self.class.request_pennylane_object(method: :put,
|
|
48
|
+
path: "/customer_invoices/#{id}",
|
|
28
49
|
params: { body: { 'invoice' => attributes } },
|
|
29
50
|
opts: {}, with: { invoice: 'customer_invoice' })
|
|
30
51
|
@values = resp.instance_variable_get :@values
|
|
31
52
|
self
|
|
32
53
|
end
|
|
33
54
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@values[:invoice]
|
|
55
|
+
def finalize
|
|
56
|
+
request_and_retrieve(method: :put, path: "/customer_invoices/#{id}", action: 'finalize')
|
|
37
57
|
end
|
|
38
58
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
59
|
+
def mark_as_paid
|
|
60
|
+
resp, opts = self.class.request_pennylane_object(method: :put,
|
|
61
|
+
path: "/customer_invoices/#{id}/mark_as_paid",
|
|
62
|
+
params: {},
|
|
63
|
+
opts: {}, with: { invoice: 'customer_invoice' })
|
|
64
|
+
@values = resp.instance_variable_get :@values
|
|
65
|
+
self
|
|
42
66
|
end
|
|
43
67
|
|
|
68
|
+
def send_by_email
|
|
69
|
+
request_and_retrieve(method: :post, path: "/customer_invoices/#{id}", action: 'send_by_email')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# When API returns an empty body
|
|
75
|
+
# so we need to skip values assignment from the response
|
|
76
|
+
# GET /customer_invoices/:id again to get the updated values
|
|
77
|
+
def request_and_retrieve(method:, path:, action:)
|
|
78
|
+
self.class.request_pennylane_object(method: method,
|
|
79
|
+
path: "#{path}/#{action}",
|
|
80
|
+
params: {},
|
|
81
|
+
opts: {}, with: { invoice: 'customer_invoice' })
|
|
82
|
+
resp, opts = self.class.request_pennylane_object(method: :get,
|
|
83
|
+
path: path,
|
|
84
|
+
params: {},
|
|
85
|
+
opts: {}, with: { invoice: 'customer_invoice' })
|
|
86
|
+
@values = resp.instance_variable_get :@values
|
|
87
|
+
self
|
|
88
|
+
end
|
|
44
89
|
end
|
|
45
90
|
end
|
data/lib/pennylane/util.rb
CHANGED
|
@@ -58,6 +58,11 @@ module Pennylane
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
def file(file_path)
|
|
62
|
+
file_data = File.open(file_path).read
|
|
63
|
+
Base64.strict_encode64(file_data)
|
|
64
|
+
end
|
|
65
|
+
|
|
61
66
|
# This method is used to convert the keys of a hash from strings to symbols
|
|
62
67
|
def symbolize_names(object)
|
|
63
68
|
case object
|
|
@@ -80,7 +85,7 @@ module Pennylane
|
|
|
80
85
|
end
|
|
81
86
|
|
|
82
87
|
def klass_for(object)
|
|
83
|
-
Pennylane::
|
|
88
|
+
Pennylane::ObjectTypes.object_names_to_classes[singularize(object)] || Pennylane::Object
|
|
84
89
|
rescue
|
|
85
90
|
Pennylane::Object
|
|
86
91
|
end
|
data/lib/pennylane/version.rb
CHANGED
data/lib/pennylane.rb
CHANGED
|
@@ -11,8 +11,9 @@ require 'forwardable'
|
|
|
11
11
|
require 'uri'
|
|
12
12
|
require 'net/http'
|
|
13
13
|
|
|
14
|
-
Dir[
|
|
14
|
+
Dir[File.join(__dir__, 'pennylane/resources/*.rb')].each {|file| require file }
|
|
15
15
|
|
|
16
|
+
require 'pennylane/object_types'
|
|
16
17
|
|
|
17
18
|
module Pennylane
|
|
18
19
|
class Error < StandardError; end
|
|
@@ -20,16 +21,6 @@ module Pennylane
|
|
|
20
21
|
class ConfigurationError < Error; end
|
|
21
22
|
class NotFoundError < Error; end
|
|
22
23
|
|
|
23
|
-
API_RESOURCES = {
|
|
24
|
-
ListObject.object_name => ListObject,
|
|
25
|
-
Category.object_name => Category,
|
|
26
|
-
CategoryGroup.object_name => CategoryGroup,
|
|
27
|
-
Customer.object_name => Customer,
|
|
28
|
-
CustomerInvoice.object_name => CustomerInvoice,
|
|
29
|
-
Product.object_name => Product,
|
|
30
|
-
Supplier.object_name => Supplier
|
|
31
|
-
}.freeze
|
|
32
|
-
|
|
33
24
|
@config = Pennylane::Configuration.new
|
|
34
25
|
# So we can have a module Pennylane that can be a class as well Pennylane.api_key = '1234'
|
|
35
26
|
class << self
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pennylane
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stephane Bounmy
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-04-
|
|
11
|
+
date: 2024-04-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: vcr
|
|
@@ -87,6 +87,7 @@ files:
|
|
|
87
87
|
- lib/pennylane/configuration.rb
|
|
88
88
|
- lib/pennylane/list_object.rb
|
|
89
89
|
- lib/pennylane/object.rb
|
|
90
|
+
- lib/pennylane/object_types.rb
|
|
90
91
|
- lib/pennylane/resources/base.rb
|
|
91
92
|
- lib/pennylane/resources/category.rb
|
|
92
93
|
- lib/pennylane/resources/category_group.rb
|
|
@@ -116,9 +117,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
116
117
|
version: 2.6.0
|
|
117
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
119
|
requirements:
|
|
119
|
-
- - "
|
|
120
|
+
- - ">="
|
|
120
121
|
- !ruby/object:Gem::Version
|
|
121
|
-
version:
|
|
122
|
+
version: '0'
|
|
122
123
|
requirements: []
|
|
123
124
|
rubygems_version: 3.4.10
|
|
124
125
|
signing_key:
|