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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.markdown +57 -29
  3. data/bin/console +15 -7
  4. data/lib/lightspeed/account.rb +44 -43
  5. data/lib/lightspeed/accounts.rb +22 -0
  6. data/lib/lightspeed/categories.rb +5 -5
  7. data/lib/lightspeed/category.rb +16 -7
  8. data/lib/lightspeed/client.rb +37 -26
  9. data/lib/lightspeed/collection.rb +218 -0
  10. data/lib/lightspeed/employee.rb +25 -0
  11. data/lib/lightspeed/employees.rb +8 -0
  12. data/lib/lightspeed/{errors.rb → error.rb} +2 -1
  13. data/lib/lightspeed/image.rb +35 -0
  14. data/lib/lightspeed/images.rb +16 -0
  15. data/lib/lightspeed/inventories.rb +8 -0
  16. data/lib/lightspeed/inventory.rb +12 -0
  17. data/lib/lightspeed/item.rb +54 -18
  18. data/lib/lightspeed/item_attribute_set.rb +13 -0
  19. data/lib/lightspeed/item_attribute_sets.rb +8 -0
  20. data/lib/lightspeed/item_matrices.rb +4 -3
  21. data/lib/lightspeed/item_matrix.rb +48 -10
  22. data/lib/lightspeed/items.rb +4 -7
  23. data/lib/lightspeed/order.rb +34 -0
  24. data/lib/lightspeed/orders.rb +10 -0
  25. data/lib/lightspeed/prices.rb +43 -0
  26. data/lib/lightspeed/request.rb +74 -28
  27. data/lib/lightspeed/request_throttler.rb +31 -0
  28. data/lib/lightspeed/resource.rb +221 -0
  29. data/lib/lightspeed/sale.rb +57 -0
  30. data/lib/lightspeed/sale_line.rb +52 -0
  31. data/lib/lightspeed/sale_lines.rb +9 -0
  32. data/lib/lightspeed/sales.rb +10 -0
  33. data/lib/lightspeed/shop.rb +30 -0
  34. data/lib/lightspeed/shops.rb +8 -0
  35. data/lib/lightspeed/special_order.rb +22 -0
  36. data/lib/lightspeed/special_orders.rb +10 -0
  37. data/lib/lightspeed/vendor.rb +23 -0
  38. data/lib/lightspeed/vendors.rb +9 -0
  39. data/lib/lightspeed/version.rb +1 -1
  40. data/lib/lightspeed_pos.rb +2 -4
  41. data/lightspeed_pos.gemspec +3 -3
  42. data/script/buildkite +11 -0
  43. data/script/docker_tests +29 -0
  44. metadata +63 -24
  45. data/lib/lightspeed/account_resources.rb +0 -103
  46. 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,9 @@
1
+ require_relative 'collection'
2
+ require_relative 'sale_line'
3
+
4
+ module Lightspeed
5
+ class SaleLines < Lightspeed::Collection
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,10 @@
1
+ require_relative 'collection'
2
+
3
+ require_relative 'sale'
4
+
5
+ module Lightspeed
6
+ class Sales < Lightspeed::Collection
7
+ alias_method :archive, :destroy
8
+ end
9
+ end
10
+
@@ -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,8 @@
1
+ require_relative 'collection'
2
+
3
+ require_relative 'shop'
4
+
5
+ module Lightspeed
6
+ class Shops < Lightspeed::Collection
7
+ end
8
+ 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
+