lightspeed_pos 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+