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,25 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
|
3
|
+
module Lightspeed
|
4
|
+
class Employee < Lightspeed::Resource
|
5
|
+
fields(
|
6
|
+
employeeID: :id,
|
7
|
+
firstName: :string,
|
8
|
+
lastName: :string,
|
9
|
+
accessPin: :string,
|
10
|
+
lockOut: :boolean,
|
11
|
+
archived: :boolean,
|
12
|
+
contactID: :integer,
|
13
|
+
clockInEmployeeHoursID: :integer,
|
14
|
+
employeeRoleID: :integer,
|
15
|
+
limitToShopID: :integer,
|
16
|
+
lastShopID: :integer,
|
17
|
+
lastSaleID: :integer,
|
18
|
+
lastRegisterID: :integer,
|
19
|
+
timeStamp: :datetime,
|
20
|
+
Contact: :hash,
|
21
|
+
EmployeeRole: :hash,
|
22
|
+
EmployeeRights: :hash
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module Lightspeed
|
2
|
-
|
2
|
+
class Error < Exception
|
3
3
|
class BadRequest < Exception; end # 400
|
4
4
|
class Unauthorized < Exception; end # 401
|
5
5
|
class NotFound < Exception; end # 404
|
6
6
|
class InternalServerError < Exception; end # 500
|
7
|
+
class Throttled < Exception; end # 503
|
7
8
|
end
|
8
9
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
|
3
|
+
require_relative 'item'
|
4
|
+
require_relative 'item_matrix'
|
5
|
+
|
6
|
+
module Lightspeed
|
7
|
+
class Image < Lightspeed::Resource
|
8
|
+
fields(
|
9
|
+
imageID: :id,
|
10
|
+
description: :string,
|
11
|
+
filename: :string,
|
12
|
+
baseImageURL: :string,
|
13
|
+
publicID: :string, # part of the file path; not a Lightspeed ID
|
14
|
+
itemID: :id,
|
15
|
+
itemMatrixID: :id,
|
16
|
+
Item: :hash,
|
17
|
+
ItemMatrix: :hash
|
18
|
+
)
|
19
|
+
|
20
|
+
relationships :Item, :ItemMatrix
|
21
|
+
|
22
|
+
def url
|
23
|
+
"#{baseImageURL}#{publicID}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def base_path
|
27
|
+
if context.is_a?(Lightspeed::Item) ||
|
28
|
+
context.is_a?(Lightspeed::ItemMatrix)
|
29
|
+
"#{context.base_path}/#{resource_name}/#{id}"
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'collection'
|
2
|
+
|
3
|
+
require_relative 'image'
|
4
|
+
|
5
|
+
module Lightspeed
|
6
|
+
class Images < Lightspeed::Collection
|
7
|
+
def base_path
|
8
|
+
if context.is_a?(Lightspeed::Item) ||
|
9
|
+
context.is_a?(Lightspeed::ItemMatrix)
|
10
|
+
"#{context.base_path}/#{resource_name}"
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/lightspeed/item.rb
CHANGED
@@ -1,26 +1,62 @@
|
|
1
|
-
require 'lightspeed/base'
|
2
1
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
require_relative 'resource'
|
3
|
+
|
4
|
+
require_relative 'item_matrix'
|
5
|
+
require_relative 'category'
|
6
|
+
require_relative 'images'
|
7
|
+
require_relative 'prices'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
module Lightspeed
|
10
|
+
class Item < Lightspeed::Resource
|
11
|
+
alias_method :archive, :destroy
|
12
12
|
|
13
|
-
|
14
|
-
:
|
13
|
+
fields(
|
14
|
+
itemID: :id,
|
15
|
+
systemSku: :string,
|
16
|
+
defaultCost: :decimal,
|
17
|
+
avgCost: :decimal,
|
18
|
+
discountable: :boolean,
|
19
|
+
tax: :boolean,
|
20
|
+
archived: :boolean,
|
21
|
+
itemType: :string,
|
22
|
+
description: :string,
|
23
|
+
modelYear: :integer,
|
24
|
+
upc: :string,
|
25
|
+
ean: :string,
|
26
|
+
customSku: :string,
|
27
|
+
manufacturerSku: :string,
|
28
|
+
createTime: :datetime,
|
29
|
+
timeStamp: :datetime,
|
30
|
+
categoryID: :id,
|
31
|
+
taxClassID: :id,
|
32
|
+
departmentID: :id,
|
33
|
+
itemMatrixID: :id,
|
34
|
+
manufacturerID: :id,
|
35
|
+
seasonID: :id,
|
36
|
+
defaultVendorID: :id,
|
37
|
+
itemECommerceID: :id,
|
38
|
+
# Category: :hash,
|
39
|
+
TaxClass: :hash,
|
40
|
+
Department: :hash,
|
41
|
+
ItemAttributes: :hash,
|
42
|
+
# ItemMatrix: :hash,
|
43
|
+
# Images: :hash,
|
44
|
+
Manufacturer: :hash,
|
45
|
+
Note: :hash,
|
46
|
+
ItemECommerce: :hash,
|
47
|
+
ItemShops: :hash,
|
48
|
+
ItemComponents: :hash,
|
49
|
+
ItemShelfLocations: :hash,
|
50
|
+
ItemVendorNums: :hash,
|
51
|
+
CustomFieldValues: :hash,
|
52
|
+
Prices: :hash,
|
53
|
+
Tags: :hash
|
54
|
+
)
|
15
55
|
|
16
|
-
|
17
|
-
"itemID"
|
18
|
-
end
|
56
|
+
relationships :ItemMatrix, :Category, :Images, DefaultVendor: :Vendor
|
19
57
|
|
20
|
-
|
21
|
-
|
22
|
-
def item_matrix
|
23
|
-
@ItemMatrix ||= owner.item_matrices.find(itemMatrixID) # rubocop:disable VariableName
|
58
|
+
def prices
|
59
|
+
@prices ||= Lightspeed::Prices.new(self.Prices)
|
24
60
|
end
|
25
61
|
end
|
26
62
|
end
|
@@ -1,8 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'collection'
|
2
|
+
|
3
|
+
require_relative 'item_matrix'
|
3
4
|
|
4
5
|
module Lightspeed
|
5
|
-
class ItemMatrices <
|
6
|
+
class ItemMatrices < Lightspeed::Collection
|
6
7
|
def self.resource_name
|
7
8
|
"ItemMatrix"
|
8
9
|
end
|
@@ -1,17 +1,55 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
|
3
|
+
require_relative 'item_attribute_set'
|
4
|
+
require_relative 'category'
|
5
|
+
require_relative 'items'
|
6
|
+
|
1
7
|
module Lightspeed
|
2
|
-
class ItemMatrix < Lightspeed::
|
3
|
-
|
4
|
-
:
|
8
|
+
class ItemMatrix < Lightspeed::Resource
|
9
|
+
fields(
|
10
|
+
itemMatrixID: :id,
|
11
|
+
description: :string,
|
12
|
+
tax: :boolean,
|
13
|
+
defaultCost: :decimal,
|
14
|
+
itemType: :string,
|
15
|
+
modelYear: :integer,
|
16
|
+
archived: :boolean,
|
17
|
+
timeStamp: :datetime,
|
18
|
+
itemAttributeSetID: :id,
|
19
|
+
manufacturerID: :id,
|
20
|
+
categoryID: :id,
|
21
|
+
defaultVendorID: :id,
|
22
|
+
taxClassID: :id,
|
23
|
+
seasonID: :id,
|
24
|
+
departmentID: :id,
|
25
|
+
itemECommerceID: :id,
|
26
|
+
itemAttributeSet: :hash,
|
27
|
+
Manufacturer: :hash,
|
28
|
+
Category: :hash,
|
29
|
+
TaxClass: :hash,
|
30
|
+
Season: :hash,
|
31
|
+
Department: :hash,
|
32
|
+
ItemECommerce: :hash,
|
33
|
+
Images: :hash,
|
34
|
+
Items: :hash,
|
35
|
+
CustomFieldValues: :hash,
|
36
|
+
Prices: :hash
|
37
|
+
)
|
38
|
+
|
39
|
+
relationships :ItemAttributeSet, :Category, :Items
|
5
40
|
|
6
|
-
#
|
7
|
-
attr_accessor :itemAttributeSetID, :manufacturerID, :categoryID, :defaultVendorID,
|
8
|
-
:taxClassID, :seasonID, :departmentID, :itemECommerceID
|
41
|
+
# overrides
|
9
42
|
|
10
|
-
|
11
|
-
|
43
|
+
def self.collection_name
|
44
|
+
'ItemMatrices'
|
45
|
+
end
|
46
|
+
|
47
|
+
def singular_path_parent
|
48
|
+
account
|
49
|
+
end
|
12
50
|
|
13
|
-
def
|
14
|
-
|
51
|
+
def prices
|
52
|
+
@prices ||= Lightspeed::Prices.new(self.Prices)
|
15
53
|
end
|
16
54
|
end
|
17
55
|
end
|
data/lib/lightspeed/items.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'collection'
|
2
|
+
|
3
|
+
require_relative 'item'
|
3
4
|
|
4
5
|
module Lightspeed
|
5
|
-
class Items < Lightspeed::
|
6
|
+
class Items < Lightspeed::Collection
|
6
7
|
alias_method :archive, :destroy
|
7
|
-
|
8
|
-
def self.resource_name
|
9
|
-
"Item"
|
10
|
-
end
|
11
8
|
end
|
12
9
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'resource'
|
2
|
+
|
3
|
+
module Lightspeed
|
4
|
+
class Order < Lightspeed::Resource
|
5
|
+
alias_method :archive, :destroy
|
6
|
+
|
7
|
+
fields(
|
8
|
+
orderID: :id,
|
9
|
+
orderedDate: :timestamp,
|
10
|
+
receivedDate: :timestamp,
|
11
|
+
arrivalDate: :timestamp,
|
12
|
+
shipInstructions: :integer,
|
13
|
+
stockInstructions: :integer,
|
14
|
+
shipCost: :decimal,
|
15
|
+
otherCost: :decimal,
|
16
|
+
complete: :boolean,
|
17
|
+
archived: :boolean,
|
18
|
+
discount: :boolean,
|
19
|
+
totalDiscount: :decimal,
|
20
|
+
totalQuantity: :decimal,
|
21
|
+
vendorID: :id,
|
22
|
+
noteID: :id,
|
23
|
+
shopID: :id,
|
24
|
+
Vendor: :hash,
|
25
|
+
Note: :hash,
|
26
|
+
Shop: :hash,
|
27
|
+
OrderLines: :hash,
|
28
|
+
CustomFieldValues: :hash,
|
29
|
+
timeStamp: :timestamp
|
30
|
+
)
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'active_support/core_ext/string'
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
module Lightspeed
|
5
|
+
class Prices
|
6
|
+
def initialize(attributes)
|
7
|
+
@attributes = attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
def prices
|
11
|
+
@prices ||= @attributes["ItemPrice"].map { |v| [v["useType"].parameterize.underscore.to_sym, BigDecimal.new(v["amount"])] }.to_h
|
12
|
+
end
|
13
|
+
|
14
|
+
def as_json
|
15
|
+
attributes
|
16
|
+
end
|
17
|
+
alias_method :to_h, :as_json
|
18
|
+
|
19
|
+
def to_json
|
20
|
+
as_json.to_json
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](key)
|
24
|
+
prices[key]
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect
|
28
|
+
prices.inspect
|
29
|
+
end
|
30
|
+
|
31
|
+
def respond_to?(method, private_method)
|
32
|
+
prices.keys.include?(method) || super
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(method, *args, &block)
|
36
|
+
if prices.keys.include?(method)
|
37
|
+
prices[method]
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/lightspeed/request.rb
CHANGED
@@ -1,55 +1,101 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'net/http'
|
3
|
+
|
1
4
|
module Lightspeed
|
2
5
|
class Request
|
3
|
-
attr_accessor :raw_request
|
6
|
+
attr_accessor :raw_request, :bucket_max, :bucket_level
|
7
|
+
|
8
|
+
SECONDS_TO_WAIT_WHEN_THROTTLED = 60 # API requirements.
|
4
9
|
|
5
|
-
|
6
|
-
|
10
|
+
class << self
|
11
|
+
attr_writer :verbose
|
7
12
|
end
|
8
13
|
|
9
|
-
def
|
10
|
-
@
|
11
|
-
|
12
|
-
method: method,
|
13
|
-
body: body,
|
14
|
-
params: params
|
15
|
-
)
|
16
|
-
|
17
|
-
if client.oauth_token
|
18
|
-
@raw_request.options[:headers].merge!(
|
19
|
-
"Authorization" => "OAuth #{client.oauth_token}"
|
20
|
-
)
|
21
|
-
end
|
14
|
+
def self.verbose?
|
15
|
+
!! @verbose
|
16
|
+
end
|
22
17
|
|
23
|
-
|
18
|
+
def self.base_host
|
19
|
+
"api.merchantos.com"
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.base_path
|
23
|
+
"/API"
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(client, method:, path:, params: nil, body: nil)
|
27
|
+
@method = method
|
28
|
+
@params = params
|
29
|
+
@path = path
|
30
|
+
@bucket_max = Float::INFINITY
|
31
|
+
@bucket_level = 0
|
32
|
+
@http = Net::HTTP.new(self.class.base_host, 443)
|
33
|
+
@http.use_ssl = true
|
34
|
+
@raw_request = request_class.new(uri)
|
35
|
+
@raw_request.body = body if body
|
36
|
+
@raw_request.set_form_data(@params) if @params && @method != :get
|
37
|
+
@raw_request["Authorization"] = "OAuth #{client.oauth_token}" if client.oauth_token
|
24
38
|
end
|
25
39
|
|
26
40
|
def perform
|
27
|
-
response = raw_request
|
28
|
-
|
41
|
+
response = @http.request(raw_request)
|
42
|
+
extract_rate_limits(response)
|
43
|
+
if response.code == "200"
|
29
44
|
handle_success(response)
|
30
45
|
else
|
31
46
|
handle_error(response)
|
32
47
|
end
|
48
|
+
rescue Lightspeed::Error::Throttled
|
49
|
+
retry_throttled_request
|
33
50
|
end
|
34
51
|
|
35
52
|
private
|
36
53
|
|
37
54
|
def handle_success(response)
|
38
|
-
JSON.parse(response.body)
|
55
|
+
json = JSON.parse(response.body)
|
56
|
+
pp json if self.class.verbose?
|
57
|
+
json
|
58
|
+
end
|
59
|
+
|
60
|
+
def retry_throttled_request
|
61
|
+
puts 'retrying throttled request after 60s.' if self.class.verbose?
|
62
|
+
sleep SECONDS_TO_WAIT_WHEN_THROTTLED
|
63
|
+
perform
|
39
64
|
end
|
40
65
|
|
41
66
|
def handle_error(response)
|
42
67
|
data = JSON.parse(response.body)
|
43
|
-
error = case response.code
|
44
|
-
when 400
|
45
|
-
|
46
|
-
when
|
47
|
-
|
48
|
-
when
|
49
|
-
|
68
|
+
error = case response.code.to_s
|
69
|
+
when '400' then Lightspeed::Error::BadRequest
|
70
|
+
when '401' then Lightspeed::Error::Unauthorized
|
71
|
+
when '404' then Lightspeed::Error::NotFound
|
72
|
+
when '429' then Lightspeed::Error::Throttled
|
73
|
+
when /5../ then Lightspeed::Error::InternalServerError
|
74
|
+
else Lightspeed::Error
|
75
|
+
end
|
76
|
+
raise error, data["message"]
|
77
|
+
end
|
78
|
+
|
79
|
+
def extract_rate_limits(response)
|
80
|
+
if bucket_headers = response["X-LS-API-Bucket-Level"]
|
81
|
+
@bucket_level, @bucket_max = bucket_headers.split("/").map(&:to_f)
|
50
82
|
end
|
83
|
+
end
|
51
84
|
|
52
|
-
|
85
|
+
def uri
|
86
|
+
uri = self.class.base_path + @path
|
87
|
+
uri += "?" + URI.encode_www_form(@params) if @params && @method == :get
|
88
|
+
uri
|
53
89
|
end
|
90
|
+
|
91
|
+
def request_class
|
92
|
+
case @method
|
93
|
+
when :get then Net::HTTP::Get
|
94
|
+
when :put then Net::HTTP::Put
|
95
|
+
when :post then Net::HTTP::Post
|
96
|
+
when :delete then Net::HTTP::Delete
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
54
100
|
end
|
55
101
|
end
|