lightspeed_pos 0.1.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.mailmap +4 -0
- data/.rubocop.yml +32 -24
- data/.rubocop_todo.yml +284 -0
- data/.travis.yml +5 -3
- data/Gemfile +2 -0
- data/README.markdown +85 -28
- data/Rakefile +2 -0
- data/bin/console +33 -6
- data/lib/lightspeed/account.rb +50 -43
- data/lib/lightspeed/accounts.rb +24 -0
- data/lib/lightspeed/categories.rb +7 -5
- data/lib/lightspeed/category.rb +18 -7
- data/lib/lightspeed/client.rb +41 -27
- data/lib/lightspeed/collection.rb +214 -0
- data/lib/lightspeed/customer.rb +36 -0
- data/lib/lightspeed/customers.rb +11 -0
- data/lib/lightspeed/employee.rb +27 -0
- data/lib/lightspeed/employees.rb +10 -0
- data/lib/lightspeed/error.rb +17 -0
- data/lib/lightspeed/image.rb +37 -0
- data/lib/lightspeed/images.rb +18 -0
- data/lib/lightspeed/inventories.rb +10 -0
- data/lib/lightspeed/inventory.rb +14 -0
- data/lib/lightspeed/item.rb +55 -18
- data/lib/lightspeed/item_attribute_set.rb +15 -0
- data/lib/lightspeed/item_attribute_sets.rb +10 -0
- data/lib/lightspeed/item_matrices.rb +6 -3
- data/lib/lightspeed/item_matrix.rb +50 -10
- data/lib/lightspeed/items.rb +6 -7
- data/lib/lightspeed/order.rb +36 -0
- data/lib/lightspeed/orders.rb +12 -0
- data/lib/lightspeed/price_level.rb +16 -0
- data/lib/lightspeed/price_levels.rb +10 -0
- data/lib/lightspeed/prices.rb +45 -0
- data/lib/lightspeed/request.rb +98 -29
- data/lib/lightspeed/request_throttler.rb +33 -0
- data/lib/lightspeed/resource.rb +221 -0
- data/lib/lightspeed/sale.rb +59 -0
- data/lib/lightspeed/sale_line.rb +54 -0
- data/lib/lightspeed/sale_lines.rb +11 -0
- data/lib/lightspeed/sales.rb +12 -0
- data/lib/lightspeed/shop.rb +32 -0
- data/lib/lightspeed/shops.rb +10 -0
- data/lib/lightspeed/special_order.rb +24 -0
- data/lib/lightspeed/special_orders.rb +12 -0
- data/lib/lightspeed/vendor.rb +25 -0
- data/lib/lightspeed/vendors.rb +11 -0
- data/lib/lightspeed/version.rb +3 -1
- data/lib/lightspeed_pos.rb +5 -5
- data/lightspeed_pos.gemspec +11 -7
- data/script/buildkite +24 -0
- data/script/docker_tests +29 -0
- metadata +96 -38
- data/lib/lightspeed/account_resources.rb +0 -103
- data/lib/lightspeed/base.rb +0 -17
- data/lib/lightspeed/errors.rb +0 -8
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -1,14 +1,41 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'dotenv'
|
6
|
+
require 'lightspeed_pos'
|
7
|
+
Lightspeed::Request.verbose = true
|
5
8
|
|
6
|
-
|
7
|
-
|
9
|
+
class TokenHolder
|
10
|
+
def initialize(token: nil, refresh_token: nil)
|
11
|
+
@token = token
|
12
|
+
@refresh_token = refresh_token
|
13
|
+
end
|
14
|
+
|
15
|
+
def oauth_token
|
16
|
+
@token
|
17
|
+
end
|
18
|
+
|
19
|
+
def refresh_oauth_token
|
20
|
+
raise "Token expired, refresh not yet implemented"
|
21
|
+
end
|
22
|
+
end
|
8
23
|
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
24
|
# require "pry"
|
11
25
|
# Pry.start
|
26
|
+
Dotenv.load
|
27
|
+
def client
|
28
|
+
token = ENV['LIGHTSPEED_OAUTH_TOKEN']
|
29
|
+
refresh_token = ENV['LIGHTSPEED_OAUTH_REFRESH_TOKEN']
|
30
|
+
raise 'set LIGHTSPEED_OAUTH_TOKEN as an envorinment variable to use this' unless token
|
31
|
+
raise 'set LIGHTSPEED_OAUTH_REFRESH_TOKEN as an envorinment variable to use this' unless refresh_token
|
32
|
+
token_holder = Tokenholder.new(token: token, refresh_token: refresh_token)
|
33
|
+
@client ||= Lightspeed::Client.new(oauth_token_holder: token_holder)
|
34
|
+
end
|
35
|
+
|
36
|
+
def account
|
37
|
+
client.accounts.first
|
38
|
+
end
|
12
39
|
|
13
|
-
require
|
40
|
+
require 'irb'
|
14
41
|
IRB.start
|
data/lib/lightspeed/account.rb
CHANGED
@@ -1,48 +1,55 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require_relative 'categories'
|
5
|
+
require_relative 'employees'
|
6
|
+
require_relative 'items'
|
7
|
+
require_relative 'item_matrices'
|
8
|
+
require_relative 'item_attribute_sets'
|
9
|
+
require_relative 'images'
|
10
|
+
require_relative 'inventories'
|
11
|
+
require_relative 'orders'
|
12
|
+
require_relative 'price_levels'
|
13
|
+
require_relative 'sales'
|
14
|
+
require_relative 'shops'
|
15
|
+
require_relative 'special_orders'
|
16
|
+
require_relative 'vendors'
|
17
|
+
require_relative 'customers'
|
5
18
|
|
6
19
|
module Lightspeed
|
7
|
-
class Account < Lightspeed::
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def category_proxy
|
41
|
-
@category_proxy ||= Lightspeed::Categories.new(self)
|
42
|
-
end
|
43
|
-
|
44
|
-
def item_matrices_proxy
|
45
|
-
@item_matrices_proxy ||= Lightspeed::ItemMatrices.new(self)
|
20
|
+
class Account < Lightspeed::Resource
|
21
|
+
fields(
|
22
|
+
accountID: :id,
|
23
|
+
name: :string,
|
24
|
+
link: :hash
|
25
|
+
)
|
26
|
+
relationships(
|
27
|
+
:Categories,
|
28
|
+
:Employees,
|
29
|
+
:Images,
|
30
|
+
:Inventories,
|
31
|
+
:ItemMatrices,
|
32
|
+
:ItemAttributeSets,
|
33
|
+
:Items,
|
34
|
+
:Orders,
|
35
|
+
:PriceLevels,
|
36
|
+
:Sales,
|
37
|
+
:Shops,
|
38
|
+
:SpecialOrders,
|
39
|
+
:Vendors,
|
40
|
+
:Customers
|
41
|
+
)
|
42
|
+
|
43
|
+
def account
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def link
|
48
|
+
if @link.is_a?(Hash)
|
49
|
+
@link['@attributes']['href']
|
50
|
+
else
|
51
|
+
@link
|
52
|
+
end
|
46
53
|
end
|
47
54
|
end
|
48
55
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'collection'
|
4
|
+
require_relative 'account'
|
5
|
+
|
6
|
+
module Lightspeed
|
7
|
+
class Accounts < Lightspeed::Collection
|
8
|
+
def base_path
|
9
|
+
'/Account'
|
10
|
+
end
|
11
|
+
|
12
|
+
def account
|
13
|
+
first_loaded || first
|
14
|
+
end
|
15
|
+
|
16
|
+
def page(n, **args)
|
17
|
+
# turns out lightspeed doesn't respect pagination for accounts.
|
18
|
+
# so page(1) is identical to page(0).
|
19
|
+
# they should be different, thus.
|
20
|
+
# if someone has more than 100 store accounts, well, good for them.
|
21
|
+
n.zero? ? super : []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'category'
|
4
|
+
require_relative 'collection'
|
3
5
|
|
4
6
|
module Lightspeed
|
5
|
-
class Categories < Lightspeed::
|
6
|
-
def
|
7
|
-
|
7
|
+
class Categories < Lightspeed::Collection
|
8
|
+
def load_relations_default
|
9
|
+
nil
|
8
10
|
end
|
9
11
|
end
|
10
12
|
end
|
data/lib/lightspeed/category.rb
CHANGED
@@ -1,10 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
:createTime
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'resource'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module Lightspeed
|
6
|
+
class Category < Lightspeed::Resource
|
7
|
+
fields(
|
8
|
+
categoryID: :id,
|
9
|
+
name: :string,
|
10
|
+
nodeDepth: :integer,
|
11
|
+
fullPathName: :string,
|
12
|
+
leftNode: :integer,
|
13
|
+
rightNode: :integer,
|
14
|
+
createTime: :datetime,
|
15
|
+
timeStamp: :datetime,
|
16
|
+
parentID: :id,
|
17
|
+
Category: :hash
|
18
|
+
)
|
19
|
+
relationships Parent: :Category
|
9
20
|
end
|
10
21
|
end
|
data/lib/lightspeed/client.rb
CHANGED
@@ -1,45 +1,59 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
|
5
|
+
require_relative 'accounts'
|
6
|
+
require_relative 'request'
|
7
|
+
require_relative 'request_throttler'
|
3
8
|
|
4
9
|
module Lightspeed
|
5
10
|
class Client
|
6
|
-
attr_accessor :
|
11
|
+
attr_accessor :throttler
|
7
12
|
|
8
|
-
def initialize(
|
9
|
-
@
|
10
|
-
@
|
11
|
-
end
|
13
|
+
def initialize(oauth_token_holder: nil, oauth_token: nil)
|
14
|
+
@oauth_token_holder = oauth_token_holder
|
15
|
+
@throttler = Lightspeed::RequestThrottler.new
|
12
16
|
|
13
|
-
|
14
|
-
Lightspeed::Request.new(self, **args)
|
17
|
+
raise "Passing an oauth token is no longer supported. Pass a token holder instead." if oauth_token
|
15
18
|
end
|
16
19
|
|
17
20
|
# Returns a list of accounts that you have access to.
|
18
21
|
def accounts
|
19
|
-
|
20
|
-
response = request.perform
|
21
|
-
instantiate(response["Account"], Lightspeed::Account)
|
22
|
+
@accounts ||= Lightspeed::Accounts.new(context: self)
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
def get(**args)
|
26
|
+
perform_request(**args, method: :get)
|
27
|
+
end
|
28
|
+
|
29
|
+
def post(**args)
|
30
|
+
perform_request(**args, method: :post)
|
31
|
+
end
|
32
|
+
|
33
|
+
def put(**args)
|
34
|
+
perform_request(**args, method: :put)
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete(**args)
|
38
|
+
perform_request(**args, method: :delete)
|
39
|
+
end
|
40
|
+
|
41
|
+
def oauth_token
|
42
|
+
@oauth_token_holder.oauth_token
|
43
|
+
end
|
44
|
+
|
45
|
+
def refresh_oauth_token
|
46
|
+
@oauth_token_holder.refresh_oauth_token
|
30
47
|
end
|
31
48
|
|
32
49
|
private
|
33
50
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# response["Category"] will not be present.
|
41
|
-
def splat(thing)
|
42
|
-
(thing.is_a?(Array) ? thing : [thing]).compact
|
51
|
+
def perform_request(**args)
|
52
|
+
@throttler.perform_request request(**args)
|
53
|
+
end
|
54
|
+
|
55
|
+
def request **args
|
56
|
+
Lightspeed::Request.new(self, **args)
|
43
57
|
end
|
44
58
|
end
|
45
59
|
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
require 'active_support/core_ext/array/wrap'
|
5
|
+
|
6
|
+
module Lightspeed
|
7
|
+
class Collection
|
8
|
+
PER_PAGE = 100 # the max page of records returned in a request
|
9
|
+
|
10
|
+
attr_accessor :context, :resources
|
11
|
+
|
12
|
+
def initialize(context:, attributes: nil)
|
13
|
+
self.context = context
|
14
|
+
instantiate(attributes)
|
15
|
+
end
|
16
|
+
|
17
|
+
def account
|
18
|
+
context.account
|
19
|
+
end
|
20
|
+
|
21
|
+
def unload
|
22
|
+
@resources = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def client
|
26
|
+
return context if context.is_a?(Lightspeed::Client)
|
27
|
+
account.client
|
28
|
+
end
|
29
|
+
|
30
|
+
def first(params: {})
|
31
|
+
params = params.merge(limit: 1)
|
32
|
+
instantiate(get(params: params)).first
|
33
|
+
end
|
34
|
+
|
35
|
+
def size(params: {})
|
36
|
+
params = params.merge(limit: 1, load_relations: nil)
|
37
|
+
get(params: params)['@attributes']['count'].to_i
|
38
|
+
end
|
39
|
+
alias_method :length, :size
|
40
|
+
|
41
|
+
def each_loaded
|
42
|
+
@resources ||= {}
|
43
|
+
@resources.each_value
|
44
|
+
end
|
45
|
+
|
46
|
+
def all_loaded
|
47
|
+
each_loaded.to_a
|
48
|
+
end
|
49
|
+
|
50
|
+
def first_loaded
|
51
|
+
each_loaded.first
|
52
|
+
end
|
53
|
+
|
54
|
+
def size_loaded
|
55
|
+
@resources.size
|
56
|
+
end
|
57
|
+
|
58
|
+
def all(params: {})
|
59
|
+
enum_page(params: params).to_a.flatten(1)
|
60
|
+
end
|
61
|
+
|
62
|
+
def each_page(per_page: PER_PAGE, params: {}, &block)
|
63
|
+
enum_page(per_page: per_page, params: params).each(&block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def enum_page(per_page: PER_PAGE, params: {})
|
67
|
+
Enumerator.new do |yielder|
|
68
|
+
loop.with_index do |_, n|
|
69
|
+
resources = page(n, per_page: per_page, params: params)
|
70
|
+
yielder << resources
|
71
|
+
raise StopIteration if resources.length < per_page
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def enum(per_page: PER_PAGE, params: {})
|
77
|
+
Enumerator.new do |yielder|
|
78
|
+
each_page(per_page: per_page, params: params) do |page|
|
79
|
+
page.each { |resource| yielder << resource }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def each(per_page: PER_PAGE, params: {}, &block)
|
85
|
+
enum(per_page: per_page, params: params).each(&block)
|
86
|
+
end
|
87
|
+
|
88
|
+
def find(id)
|
89
|
+
first(params: { resource_class.id_field => id }) || handle_not_found(id)
|
90
|
+
end
|
91
|
+
|
92
|
+
def create(attributes = {})
|
93
|
+
instantiate(post(body: Yajl::Encoder.encode(attributes))).first
|
94
|
+
end
|
95
|
+
|
96
|
+
def update(id, attributes = {})
|
97
|
+
instantiate(put(id, body: Yajl::Encoder.encode(attributes))).first
|
98
|
+
end
|
99
|
+
|
100
|
+
def destroy(id)
|
101
|
+
instantiate(delete(id)).first
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.collection_name
|
105
|
+
name.demodulize
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.resource_name
|
109
|
+
collection_name.singularize
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.resource_class
|
113
|
+
"Lightspeed::#{resource_name}".constantize
|
114
|
+
end
|
115
|
+
|
116
|
+
def base_path
|
117
|
+
"#{account.base_path}/#{resource_name}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def inspect
|
121
|
+
"#<#{self.class.name} API#{base_path}>"
|
122
|
+
end
|
123
|
+
|
124
|
+
def as_json
|
125
|
+
return if all_loaded.empty?
|
126
|
+
{ resource_name => all_loaded.as_json }
|
127
|
+
end
|
128
|
+
alias_method :to_h, :as_json
|
129
|
+
|
130
|
+
def to_json
|
131
|
+
Yajl::Encoder.encode(as_json)
|
132
|
+
end
|
133
|
+
|
134
|
+
def page(n, per_page: PER_PAGE, params: {})
|
135
|
+
params = params.merge(limit: per_page, offset: per_page * n)
|
136
|
+
instantiate(get(params: params))
|
137
|
+
end
|
138
|
+
|
139
|
+
def load_relations_default
|
140
|
+
'all'
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def handle_not_found(id)
|
146
|
+
raise Lightspeed::Error::NotFound, "Could not find a #{resource_name} with #{resource_class.id_field}=#{id}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def context_params
|
150
|
+
if context.class.respond_to?(:id_field) &&
|
151
|
+
resource_class.method_defined?(context.class.id_field.to_sym)
|
152
|
+
{ context.class.id_field => context.id }
|
153
|
+
else
|
154
|
+
{}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def instantiate(response)
|
159
|
+
return [] unless response.is_a?(Hash)
|
160
|
+
@resources ||= {}
|
161
|
+
Array.wrap(response[resource_name]).map do |resource|
|
162
|
+
resource = resource_class.new(context: self, attributes: resource)
|
163
|
+
@resources[resource.id] = resource
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def resource_class
|
168
|
+
self.class.resource_class
|
169
|
+
end
|
170
|
+
|
171
|
+
def resource_name
|
172
|
+
self.class.resource_name
|
173
|
+
end
|
174
|
+
|
175
|
+
def get(params: {})
|
176
|
+
params = { load_relations: load_relations_default }
|
177
|
+
.merge(context_params)
|
178
|
+
.merge(params)
|
179
|
+
.compact
|
180
|
+
client.get(
|
181
|
+
path: collection_path,
|
182
|
+
params: params
|
183
|
+
)
|
184
|
+
end
|
185
|
+
|
186
|
+
def post(body:)
|
187
|
+
client.post(
|
188
|
+
path: collection_path,
|
189
|
+
body: body
|
190
|
+
)
|
191
|
+
end
|
192
|
+
|
193
|
+
def put(id, body:)
|
194
|
+
client.put(
|
195
|
+
path: resource_path(id),
|
196
|
+
body: body
|
197
|
+
)
|
198
|
+
end
|
199
|
+
|
200
|
+
def delete(id)
|
201
|
+
client.delete(
|
202
|
+
path: resource_path(id)
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
def collection_path
|
207
|
+
"#{base_path}.json"
|
208
|
+
end
|
209
|
+
|
210
|
+
def resource_path(id)
|
211
|
+
"#{base_path}/#{id}.json"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|