lightspeed_pos 0.1.0 → 0.2.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 +4 -4
- data/README.markdown +57 -29
- data/bin/console +15 -7
- data/lib/lightspeed/account.rb +44 -43
- data/lib/lightspeed/accounts.rb +22 -0
- data/lib/lightspeed/categories.rb +5 -5
- data/lib/lightspeed/category.rb +16 -7
- data/lib/lightspeed/client.rb +37 -26
- data/lib/lightspeed/collection.rb +218 -0
- data/lib/lightspeed/employee.rb +25 -0
- data/lib/lightspeed/employees.rb +8 -0
- data/lib/lightspeed/{errors.rb → error.rb} +2 -1
- data/lib/lightspeed/image.rb +35 -0
- data/lib/lightspeed/images.rb +16 -0
- data/lib/lightspeed/inventories.rb +8 -0
- data/lib/lightspeed/inventory.rb +12 -0
- data/lib/lightspeed/item.rb +54 -18
- data/lib/lightspeed/item_attribute_set.rb +13 -0
- data/lib/lightspeed/item_attribute_sets.rb +8 -0
- data/lib/lightspeed/item_matrices.rb +4 -3
- data/lib/lightspeed/item_matrix.rb +48 -10
- data/lib/lightspeed/items.rb +4 -7
- data/lib/lightspeed/order.rb +34 -0
- data/lib/lightspeed/orders.rb +10 -0
- data/lib/lightspeed/prices.rb +43 -0
- data/lib/lightspeed/request.rb +74 -28
- data/lib/lightspeed/request_throttler.rb +31 -0
- data/lib/lightspeed/resource.rb +221 -0
- data/lib/lightspeed/sale.rb +57 -0
- data/lib/lightspeed/sale_line.rb +52 -0
- data/lib/lightspeed/sale_lines.rb +9 -0
- data/lib/lightspeed/sales.rb +10 -0
- data/lib/lightspeed/shop.rb +30 -0
- data/lib/lightspeed/shops.rb +8 -0
- data/lib/lightspeed/special_order.rb +22 -0
- data/lib/lightspeed/special_orders.rb +10 -0
- data/lib/lightspeed/vendor.rb +23 -0
- data/lib/lightspeed/vendors.rb +9 -0
- data/lib/lightspeed/version.rb +1 -1
- data/lib/lightspeed_pos.rb +2 -4
- data/lightspeed_pos.gemspec +3 -3
- data/script/buildkite +11 -0
- data/script/docker_tests +29 -0
- metadata +63 -24
- data/lib/lightspeed/account_resources.rb +0 -103
- data/lib/lightspeed/base.rb +0 -17
@@ -0,0 +1,31 @@
|
|
1
|
+
module Lightspeed
|
2
|
+
class RequestThrottler
|
3
|
+
attr_accessor :bucket_level, :bucket_max, :units_per_second
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@units_per_second = 0.5
|
7
|
+
@bucket_max = Float::INFINITY
|
8
|
+
@bucket_level = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def perform_request request
|
12
|
+
u = units request
|
13
|
+
sleep(u / @units_per_second) if @bucket_level + u > @bucket_max
|
14
|
+
response = request.perform
|
15
|
+
extract_rate_limits request
|
16
|
+
response
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def units request
|
22
|
+
if request.raw_request.is_a? Net::HTTP::Get then 1 else 10 end
|
23
|
+
end
|
24
|
+
|
25
|
+
def extract_rate_limits request
|
26
|
+
@bucket_max, @bucket_level = request.bucket_max, request.bucket_level
|
27
|
+
@units_per_second = @bucket_max/60.0
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
require 'active_support/core_ext/hash/slice'
|
4
|
+
require 'active_support/json'
|
5
|
+
require 'active_support/core_ext/object/json'
|
6
|
+
|
7
|
+
require_relative 'collection'
|
8
|
+
|
9
|
+
module Lightspeed
|
10
|
+
class ID < Integer; end
|
11
|
+
class Link; end
|
12
|
+
class Resource
|
13
|
+
attr_accessor :id, :attributes, :client, :context, :account
|
14
|
+
|
15
|
+
def initialize(client: nil, context: nil, attributes: {})
|
16
|
+
self.client = client
|
17
|
+
self.context = context
|
18
|
+
self.attributes = attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
def attributes=(attributes)
|
22
|
+
@attributes = attributes
|
23
|
+
attributes.each do |key, value|
|
24
|
+
send(:"#{key}=", value) if self.respond_to?(:"#{key}=")
|
25
|
+
end
|
26
|
+
self.id = send(self.class.id_field)
|
27
|
+
attributes
|
28
|
+
end
|
29
|
+
|
30
|
+
def account
|
31
|
+
@account || context.try(:account)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.fields(fields = {})
|
35
|
+
@fields ||= []
|
36
|
+
attr_writer(*fields.keys)
|
37
|
+
fields.each do |name, klass|
|
38
|
+
@fields << define_method(name) do
|
39
|
+
get_transformed_value(name, klass)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@fields
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_transformed_value(name, kind)
|
46
|
+
value = instance_variable_get("@#{name}")
|
47
|
+
if value.is_a?(String)
|
48
|
+
case kind
|
49
|
+
when :string then value
|
50
|
+
when :integer then value.to_i
|
51
|
+
when :id then value.to_i
|
52
|
+
when :datetime then DateTime.parse(value)
|
53
|
+
when :boolean then value == 'true'
|
54
|
+
when :decimal then BigDecimal.new(value)
|
55
|
+
when :hash then Hash.new(value)
|
56
|
+
else
|
57
|
+
raise ArgumentError, "Could not transform value #{value} to a #{kind}"
|
58
|
+
end
|
59
|
+
else
|
60
|
+
value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def client
|
65
|
+
@client || context.try(:client)
|
66
|
+
end
|
67
|
+
|
68
|
+
def load
|
69
|
+
self.attributes = get[resource_name] if (attributes.keys - [self.class.id_field]).empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
def reload
|
73
|
+
self.attributes = get[resource_name]
|
74
|
+
end
|
75
|
+
|
76
|
+
def update(attributes = {})
|
77
|
+
self.attributes = put(body: attributes.to_json)[resource_name]
|
78
|
+
end
|
79
|
+
|
80
|
+
def destroy
|
81
|
+
self.attributes = delete[resource_name]
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.resource_name
|
86
|
+
name.demodulize
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.collection_name
|
90
|
+
resource_name.pluralize
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.id_field
|
94
|
+
"#{resource_name.camelize(:lower)}ID"
|
95
|
+
end
|
96
|
+
|
97
|
+
def id_params
|
98
|
+
{ self.class.id_field => id }
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.relationships(*args)
|
102
|
+
@relationships ||= []
|
103
|
+
paired_args = args.flat_map { |r| r.is_a?(Hash) ? r.to_a : [[r, r]] }
|
104
|
+
paired_args.each do |(relation_name, class_name)|
|
105
|
+
method_name = relation_name.to_s.underscore.to_sym
|
106
|
+
@relationships << define_method(method_name) do
|
107
|
+
instance_variable_get("@#{method_name}") || get_relation(method_name, relation_name, class_name)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
@relationships
|
111
|
+
end
|
112
|
+
|
113
|
+
def inspect
|
114
|
+
"#<#{self.class.name} API#{base_path}>"
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
def to_json(*args)
|
119
|
+
as_json.to_json(*args)
|
120
|
+
end
|
121
|
+
|
122
|
+
def as_json(*args)
|
123
|
+
fields_to_h.merge(relationships_to_h).reject { |_, v| v.nil? || v == {} }.as_json(*args)
|
124
|
+
end
|
125
|
+
alias_method :to_h, :as_json
|
126
|
+
|
127
|
+
def base_path
|
128
|
+
if context.is_a?(Lightspeed::Collection)
|
129
|
+
"#{context.base_path}/#{id}"
|
130
|
+
else
|
131
|
+
"#{account.base_path}/#{resource_name}/#{id}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def singular_path_parent
|
136
|
+
context
|
137
|
+
end
|
138
|
+
|
139
|
+
def resource_name
|
140
|
+
self.class.resource_name
|
141
|
+
end
|
142
|
+
|
143
|
+
def read_attribute_for_serialization(method_name)
|
144
|
+
method_name = method_name.to_sym
|
145
|
+
|
146
|
+
if self.class.fields.include?(method_name) || self.class.relationships.include?(method_name)
|
147
|
+
send(method_name)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def fields_to_h
|
154
|
+
self.class.fields.map { |f| [f, send(f)] }.to_h
|
155
|
+
end
|
156
|
+
|
157
|
+
def relationships_to_h
|
158
|
+
self.class.relationships.map { |r| [r.to_s.camelize, send(r).to_h] }.to_h
|
159
|
+
end
|
160
|
+
|
161
|
+
def collection_class
|
162
|
+
"Lightspeed::#{self.class.collection_name}".constantize
|
163
|
+
end
|
164
|
+
|
165
|
+
def get_relation(method_name, relation_name, class_name)
|
166
|
+
klass = "Lightspeed::#{class_name}".constantize
|
167
|
+
case
|
168
|
+
when klass <= Lightspeed::Collection then get_collection_relation(method_name, relation_name, klass)
|
169
|
+
when klass <= Lightspeed::Resource then get_resource_relation(method_name, relation_name, klass)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_collection_relation(method_name, relation_name, klass)
|
174
|
+
collection = klass.new(context: self, attributes: attributes[relation_name.to_s])
|
175
|
+
instance_variable_set("@#{method_name}", collection)
|
176
|
+
end
|
177
|
+
|
178
|
+
def get_resource_relation(method_name, relation_name, klass)
|
179
|
+
id_field = "#{relation_name.to_s.camelize(:lower)}ID" # parentID != #categoryID, so we can't use klass.id_field
|
180
|
+
resource = if send(id_field).to_i.nonzero?
|
181
|
+
rel_attributes = attributes[klass.resource_name] || { klass.id_field => send(id_field) }
|
182
|
+
klass.new(context: self, attributes: rel_attributes).tap(&:load)
|
183
|
+
end
|
184
|
+
instance_variable_set("@#{method_name}", resource)
|
185
|
+
end
|
186
|
+
|
187
|
+
def context_params
|
188
|
+
if context.respond_to?(:id_field) &&
|
189
|
+
respond_to?(context.id_field.to_sym)
|
190
|
+
{ context.id_field => context.id }
|
191
|
+
else
|
192
|
+
{}
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def get(params: {})
|
197
|
+
params = { load_relations: 'all' }.merge(context_params).merge(params)
|
198
|
+
client.get(
|
199
|
+
path: resource_path,
|
200
|
+
params: params
|
201
|
+
)
|
202
|
+
end
|
203
|
+
|
204
|
+
def put(body:)
|
205
|
+
client.put(
|
206
|
+
path: resource_path,
|
207
|
+
body: body
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
def delete
|
212
|
+
client.delete(
|
213
|
+
path: resource_path
|
214
|
+
)
|
215
|
+
end
|
216
|
+
|
217
|
+
def resource_path
|
218
|
+
"#{base_path}.json"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
|
3
|
+
require_relative 'sale_lines'
|
4
|
+
|
5
|
+
module Lightspeed
|
6
|
+
class Sale < Lightspeed::Resource
|
7
|
+
alias_method :archive, :destroy
|
8
|
+
|
9
|
+
fields(
|
10
|
+
saleID: :id,
|
11
|
+
timeStamp: :datetime,
|
12
|
+
discountPercent: :decimal,
|
13
|
+
completed: :boolean,
|
14
|
+
archived: :boolean,
|
15
|
+
voided: :boolean,
|
16
|
+
enablePromotions: :boolean,
|
17
|
+
referenceNumber: :string,
|
18
|
+
referenceNumberSource: :string,
|
19
|
+
tax1Rate: :decimal,
|
20
|
+
tax2Rate: :decimal,
|
21
|
+
change: :decimal,
|
22
|
+
calcDiscount: :decimal,
|
23
|
+
calcTotal: :decimal,
|
24
|
+
calcSubtotal: :decimal,
|
25
|
+
calcTaxable: :decimal,
|
26
|
+
calcNonTaxable: :decimal,
|
27
|
+
calcAvgCost: :decimal,
|
28
|
+
calcFIFOCost: :decimal,
|
29
|
+
calcTax1: :decimal,
|
30
|
+
calcTax2: :decimal,
|
31
|
+
calcPayments: :decimal,
|
32
|
+
total: :decimal,
|
33
|
+
totalDue: :decimal,
|
34
|
+
displayableTotal: :decimal,
|
35
|
+
balance: :decimal,
|
36
|
+
customerID: :id,
|
37
|
+
discountID: :id,
|
38
|
+
employeeID: :id,
|
39
|
+
quoteID: :id,
|
40
|
+
registerID: :id,
|
41
|
+
shipToID: :id,
|
42
|
+
shopID: :id,
|
43
|
+
taxCategoryID: :id,
|
44
|
+
Customer: :hash,
|
45
|
+
Discount: :hash,
|
46
|
+
Quote: :hash,
|
47
|
+
ShipTo: :hash,
|
48
|
+
TaxCategory: :hash,
|
49
|
+
# SaleLines: :integer,
|
50
|
+
SalePayments: :hash
|
51
|
+
)
|
52
|
+
|
53
|
+
relationships :SaleLines, :Employee
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
require_relative 'item'
|
3
|
+
|
4
|
+
module Lightspeed
|
5
|
+
class SaleLine < Lightspeed::Resource
|
6
|
+
|
7
|
+
fields(
|
8
|
+
saleLineID: :id,
|
9
|
+
createTime: :datetime,
|
10
|
+
timeStamp: :datetime,
|
11
|
+
unitQuantity: :integer,
|
12
|
+
unitPrice: :decimal,
|
13
|
+
normalUnitPrice: :decimal,
|
14
|
+
discountAmount: :decimal,
|
15
|
+
discountPercent: :decimal,
|
16
|
+
avgCost: :decimal,
|
17
|
+
fifoCost: :decimal,
|
18
|
+
tax: :boolean,
|
19
|
+
tax1Rate: :decimal,
|
20
|
+
tax2Rate: :decimal,
|
21
|
+
isLayaway: :boolean,
|
22
|
+
isWorkorder: :boolean,
|
23
|
+
isSpecialOrder: :boolean,
|
24
|
+
displayableSubtotal: :decimal,
|
25
|
+
displayableUnitPrice: :decimal,
|
26
|
+
calcLineDiscount: :decimal,
|
27
|
+
calcTransactionDiscount: :decimal,
|
28
|
+
calcTotal: :decimal,
|
29
|
+
calcSubtotal: :decimal,
|
30
|
+
calcTax1: :decimal,
|
31
|
+
calcTax2: :decimal,
|
32
|
+
taxClassID: :id,
|
33
|
+
customerID: :id,
|
34
|
+
discountID: :id,
|
35
|
+
employeeID: :id,
|
36
|
+
itemID: :id,
|
37
|
+
noteID: :id,
|
38
|
+
parentSaleLineID: :id,
|
39
|
+
shopID: :id,
|
40
|
+
saleID: :id,
|
41
|
+
TaxClass: :hash,
|
42
|
+
Discount: :hash,
|
43
|
+
# Item: :hash,
|
44
|
+
Note: :hash
|
45
|
+
)
|
46
|
+
|
47
|
+
relationships :Item
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
|
3
|
+
module Lightspeed
|
4
|
+
class Shop < Lightspeed::Resource
|
5
|
+
fields(
|
6
|
+
shopID: :id,
|
7
|
+
name: :string,
|
8
|
+
serviceRate: :decimal,
|
9
|
+
timeZone: :string,
|
10
|
+
taxLabor: :boolean,
|
11
|
+
labelTitle: :string,
|
12
|
+
labelMsrp: :boolean,
|
13
|
+
archived: :boolean,
|
14
|
+
contactID: :id,
|
15
|
+
taxCategoryID: :id,
|
16
|
+
receiptSetupID: :id,
|
17
|
+
ccGatewayID: :id,
|
18
|
+
priceLevelID: :id,
|
19
|
+
Contact: :hash,
|
20
|
+
TaxCategory: :hash, # requestable object.
|
21
|
+
ReceiptSetup: :hash,
|
22
|
+
CCGateway: :hash, # requestable object
|
23
|
+
PriceLevel: :hash, # requestable object.
|
24
|
+
ShelfLocations: :hash,
|
25
|
+
Registers: :hash
|
26
|
+
)
|
27
|
+
|
28
|
+
relationships :Items
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
|
3
|
+
module Lightspeed
|
4
|
+
class SpecialOrder < Lightspeed::Resource
|
5
|
+
fields(
|
6
|
+
specialOrderID: :id,
|
7
|
+
qout: :integer,
|
8
|
+
contacted: :boolean,
|
9
|
+
completed: :boolean,
|
10
|
+
customerID: :id,
|
11
|
+
shopID: :id,
|
12
|
+
saleLineID: :id,
|
13
|
+
orderLineID: :id,
|
14
|
+
transferItemID: :id,
|
15
|
+
OrderLine: :hash
|
16
|
+
)
|
17
|
+
|
18
|
+
relationships :SaleLine, :Shop
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|