lightspeed_pos 0.1.0 → 0.6.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.
- 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
|