rbvore 0.1.1
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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +22 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +114 -0
- data/LICENSE.txt +21 -0
- data/README.md +71 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/setup +8 -0
- data/lib/rbvore.rb +52 -0
- data/lib/rbvore/api.rb +158 -0
- data/lib/rbvore/discount.rb +12 -0
- data/lib/rbvore/employee.rb +12 -0
- data/lib/rbvore/item.rb +16 -0
- data/lib/rbvore/item_modifier.rb +11 -0
- data/lib/rbvore/link.rb +50 -0
- data/lib/rbvore/location.rb +22 -0
- data/lib/rbvore/menu_category.rb +11 -0
- data/lib/rbvore/menu_item.rb +13 -0
- data/lib/rbvore/order_type.rb +11 -0
- data/lib/rbvore/payment.rb +39 -0
- data/lib/rbvore/resource.rb +95 -0
- data/lib/rbvore/resource/fetchers.rb +51 -0
- data/lib/rbvore/resource/names.rb +35 -0
- data/lib/rbvore/resource/parsers.rb +35 -0
- data/lib/rbvore/revenue_center.rb +11 -0
- data/lib/rbvore/table.rb +13 -0
- data/lib/rbvore/tender_type.rb +11 -0
- data/lib/rbvore/ticket.rb +46 -0
- data/lib/rbvore/ticket_discount.rb +12 -0
- data/lib/rbvore/ticket_service_charge.rb +23 -0
- data/lib/rbvore/version.rb +5 -0
- data/rbvore.gemspec +32 -0
- metadata +126 -0
data/lib/rbvore.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rbvore/version"
|
4
|
+
|
5
|
+
module Rbvore
|
6
|
+
class Error < StandardError; end
|
7
|
+
# Your code goes here...
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'rbvore/api'
|
11
|
+
require 'rbvore/link'
|
12
|
+
require 'rbvore/resource'
|
13
|
+
require 'rbvore/discount'
|
14
|
+
require 'rbvore/menu_category'
|
15
|
+
require 'rbvore/menu_item'
|
16
|
+
require 'rbvore/item_modifier'
|
17
|
+
require 'rbvore/item'
|
18
|
+
require 'rbvore/tender_type'
|
19
|
+
require 'rbvore/payment'
|
20
|
+
require 'rbvore/table'
|
21
|
+
require 'rbvore/employee'
|
22
|
+
require 'rbvore/ticket_service_charge'
|
23
|
+
require 'rbvore/ticket_discount'
|
24
|
+
require 'rbvore/order_type'
|
25
|
+
require 'rbvore/revenue_center'
|
26
|
+
require 'rbvore/ticket'
|
27
|
+
require 'rbvore/location'
|
28
|
+
|
29
|
+
module Rbvore
|
30
|
+
def self.resource_subclass?(klass)
|
31
|
+
klass.respond_to?(:superclass) && klass.superclass == Resource
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.resource_classes
|
35
|
+
@resource_classes ||= Rbvore.constants.map { |const|
|
36
|
+
klass = Rbvore.const_get(const)
|
37
|
+
klass if resource_subclass?(klass)
|
38
|
+
}.compact
|
39
|
+
end
|
40
|
+
|
41
|
+
# constantize attempts to turn a class name string into a proper constant that
|
42
|
+
# is a subclass of Rbvore::Resource
|
43
|
+
def self.constantize(name)
|
44
|
+
return name if resource_subclass?(name)
|
45
|
+
|
46
|
+
resource_classes.each do |klass|
|
47
|
+
return klass if [klass.singularize, klass.list_name, klass.pluralize].include?(name.to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
raise Rbvore::Error, "No Rbvore resource classes found for #{name.inspect}"
|
51
|
+
end
|
52
|
+
end
|
data/lib/rbvore/api.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'net/http'
|
5
|
+
require 'json'
|
6
|
+
require 'forwardable'
|
7
|
+
require 'cgi'
|
8
|
+
|
9
|
+
module Rbvore
|
10
|
+
class API
|
11
|
+
DEFAULT_HOST = ENV.fetch("OMNIVORE_HOST", "api.omnivore.io")
|
12
|
+
DEFAULT_API_KEY = ENV.fetch("OMNIVORE_API_KEY", nil)
|
13
|
+
BASE_ENDPOINT = "/1.0"
|
14
|
+
|
15
|
+
class Error < Error
|
16
|
+
extend Forwardable
|
17
|
+
attr_reader :response
|
18
|
+
def_delegators :response, :code, :body, :json_body, :uri
|
19
|
+
|
20
|
+
def initialize(message = nil, response:)
|
21
|
+
@response = response
|
22
|
+
@message = message || [response.code, response.message].join(" ")
|
23
|
+
super(@message)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Response
|
28
|
+
extend Forwardable
|
29
|
+
|
30
|
+
attr_reader :original
|
31
|
+
def_delegators :original, :code, :body, :uri, :msg, :message, :inspect, :content_type
|
32
|
+
|
33
|
+
def initialize(obj)
|
34
|
+
@original = obj
|
35
|
+
end
|
36
|
+
|
37
|
+
def json_body
|
38
|
+
@json_body ||= JSON.parse(body)
|
39
|
+
end
|
40
|
+
|
41
|
+
def success?
|
42
|
+
original.is_a?(Net::HTTPSuccess)
|
43
|
+
end
|
44
|
+
|
45
|
+
def error
|
46
|
+
API::Error.new(response: self) unless success?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(host = DEFAULT_HOST)
|
51
|
+
@host = host
|
52
|
+
end
|
53
|
+
|
54
|
+
def request(method, endpoint, body: nil, params: {}, headers: {}, api_key: nil) # rubocop:disable Metrics/ParameterLists
|
55
|
+
api_key ||= DEFAULT_API_KEY
|
56
|
+
uri = build_uri(endpoint, params)
|
57
|
+
http_start(uri) { |http|
|
58
|
+
http.request(
|
59
|
+
build_request(method, uri, body: body, headers: headers, api_key: api_key),
|
60
|
+
)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def fetch_all(endpoint, resource_class, params: {}, api_key: nil)
|
65
|
+
response = request(
|
66
|
+
:get,
|
67
|
+
endpoint,
|
68
|
+
params: params,
|
69
|
+
api_key: api_key,
|
70
|
+
)
|
71
|
+
raise response.error unless response.success?
|
72
|
+
|
73
|
+
Resource.parse_collection(response.json_body, resource_class)
|
74
|
+
end
|
75
|
+
|
76
|
+
def fetch_one(endpoint, resource_class, params: {}, api_key: nil)
|
77
|
+
response = request(
|
78
|
+
:get,
|
79
|
+
endpoint,
|
80
|
+
params: params,
|
81
|
+
api_key: api_key,
|
82
|
+
)
|
83
|
+
raise response.error unless response.success?
|
84
|
+
|
85
|
+
Resource.parse_object(response.json_body, resource_class)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.endpoint(*items)
|
89
|
+
([BASE_ENDPOINT] + items.map { |item|
|
90
|
+
case
|
91
|
+
when Rbvore.resource_subclass?(item)
|
92
|
+
item.pluralize
|
93
|
+
when item.nil?
|
94
|
+
nil
|
95
|
+
else
|
96
|
+
item.to_s
|
97
|
+
end
|
98
|
+
}.compact).join("/")
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def build_uri(endpoint, params = nil)
|
104
|
+
url = if endpoint.start_with? "http"
|
105
|
+
endpoint
|
106
|
+
else
|
107
|
+
"https://#{@host}#{endpoint}"
|
108
|
+
end
|
109
|
+
|
110
|
+
URI.parse(url).tap { |uri|
|
111
|
+
next if params.nil? || params.empty?
|
112
|
+
|
113
|
+
uri.query = encode_form_data(params)
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def encode_form_data(body)
|
118
|
+
body.map { |key, value| "#{key}=#{CGI.escape(value)}" }.join("&")
|
119
|
+
end
|
120
|
+
|
121
|
+
def build_request(method, uri, body: nil, headers: {}, api_key: nil)
|
122
|
+
method_class(method).new(uri.request_uri).tap { |r|
|
123
|
+
headers.each do |key, value|
|
124
|
+
r.add_field(key, value)
|
125
|
+
end
|
126
|
+
r.add_field "Accept", "application/json"
|
127
|
+
r.add_field "Api-Key", api_key unless api_key.nil?
|
128
|
+
set_body(r, body)
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
def http_start(uri, &block)
|
133
|
+
Response.new(Net::HTTP.start(uri.host, uri.port, http_opts, &block))
|
134
|
+
end
|
135
|
+
|
136
|
+
def http_opts
|
137
|
+
{ use_ssl: true }
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_body(request, body)
|
141
|
+
if body.is_a? String
|
142
|
+
request.body = body
|
143
|
+
elsif !body.nil?
|
144
|
+
request.add_field "Content-Type", "application/json"
|
145
|
+
request.body = body.to_json
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def method_class(name)
|
150
|
+
case name.to_sym
|
151
|
+
when :get
|
152
|
+
Net::HTTP::Get
|
153
|
+
when :post
|
154
|
+
Net::HTTP::Post
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rbvore
|
4
|
+
class Discount < Resource
|
5
|
+
attr_accessor :id, :available, :max_amount, :max_percent, :min_amount, :min_percent,
|
6
|
+
:min_ticket_total, :name, :open, :pos_id, :type, :value, :applies_to
|
7
|
+
|
8
|
+
def initialize(hash)
|
9
|
+
set_attributes(hash)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/rbvore/item.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rbvore
|
4
|
+
class Item < Resource
|
5
|
+
attr_accessor :id, :name, :price, :quantity, :seat, :sent, :split, :comment
|
6
|
+
attr_timestamp_accessor :sent_at
|
7
|
+
attr_objects menu_item: MenuItem
|
8
|
+
attr_collections modifiers: ItemModifier, discounts: Discount
|
9
|
+
|
10
|
+
def initialize(hash)
|
11
|
+
set_attributes(hash)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class VoidedItem < Item; end
|
16
|
+
end
|
data/lib/rbvore/link.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rbvore
|
4
|
+
class UnknownLinkError < Error; end
|
5
|
+
|
6
|
+
class Link
|
7
|
+
attr_accessor :href, :type
|
8
|
+
|
9
|
+
def initialize(hash)
|
10
|
+
self.href = hash["href"]
|
11
|
+
self.type = hash["type"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def type_name
|
15
|
+
@type_name ||= type.match(/name=(?<name>[a-z\_]+)/).named_captures["name"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def resource_class
|
19
|
+
Rbvore.constantize(type_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def list?
|
23
|
+
type_name.end_with? "list"
|
24
|
+
end
|
25
|
+
|
26
|
+
def api
|
27
|
+
@api ||= API.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def fetch(api_key: nil, params: {})
|
31
|
+
response = api.request(
|
32
|
+
:get,
|
33
|
+
href,
|
34
|
+
params: params,
|
35
|
+
api_key: api_key,
|
36
|
+
)
|
37
|
+
raise response.error unless response.success?
|
38
|
+
|
39
|
+
parse_resources(response.json_body)
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_resources(json_body)
|
43
|
+
if list?
|
44
|
+
Resource.parse_collection(json_body, resource_class)
|
45
|
+
else
|
46
|
+
Resource.parse_object(json_body, resource_class)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rbvore
|
4
|
+
class Location < Resource
|
5
|
+
attr_accessor :address, :concept_name, :display_name, :name, :id, :custom_id,
|
6
|
+
:google_place_id, :health, :latitude, :longitude, :owner, :phone,
|
7
|
+
:pos_type, :status, :timezone, :website, :development
|
8
|
+
attr_timestamp_accessor :created, :modified
|
9
|
+
attr_collections(
|
10
|
+
tender_types: TenderType,
|
11
|
+
employees: Employee,
|
12
|
+
tables: Table,
|
13
|
+
order_types: OrderType,
|
14
|
+
revenue_centers: RevenueCenter,
|
15
|
+
tickets: Ticket,
|
16
|
+
)
|
17
|
+
|
18
|
+
def initialize(hash)
|
19
|
+
set_attributes(hash)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rbvore
|
4
|
+
class MenuItem < Resource
|
5
|
+
attr_accessor :id, :barcodes, :in_stock, :name, :open, :pos_id, :price_per_unit
|
6
|
+
|
7
|
+
attr_collections menu_categories: MenuCategory
|
8
|
+
|
9
|
+
def initialize(hash)
|
10
|
+
set_attributes(hash)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rbvore
|
4
|
+
class Payment < Resource
|
5
|
+
attr_accessor :id, :amount, :change, :comment, :full_name, :status, :last4, :tip, :type
|
6
|
+
attr_objects tender_type: TenderType
|
7
|
+
|
8
|
+
def initialize(hash)
|
9
|
+
set_attributes(hash)
|
10
|
+
end
|
11
|
+
|
12
|
+
def api
|
13
|
+
@api ||= API.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_3rd_party(location_id:, ticket_id:, auto_close: false, api_key: nil)
|
17
|
+
response = api.request(
|
18
|
+
:post,
|
19
|
+
self.class.endpoint(location_id: location_id, ticket_id: ticket_id),
|
20
|
+
body: third_party_body(auto_close),
|
21
|
+
api_key: api_key,
|
22
|
+
)
|
23
|
+
raise response.error unless response.success?
|
24
|
+
|
25
|
+
Payment.new(response.json_body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def third_party_body(auto_close)
|
29
|
+
{
|
30
|
+
amount: amount,
|
31
|
+
tip: tip,
|
32
|
+
tender_type: tender_type,
|
33
|
+
auto_close: auto_close,
|
34
|
+
comment: comment,
|
35
|
+
type: "3rd_party",
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rbvore/resource/parsers'
|
4
|
+
require 'rbvore/resource/names'
|
5
|
+
require 'rbvore/resource/fetchers'
|
6
|
+
|
7
|
+
module Rbvore
|
8
|
+
class Resource
|
9
|
+
extend Names
|
10
|
+
extend Fetchers
|
11
|
+
extend Parsers
|
12
|
+
include Parsers
|
13
|
+
|
14
|
+
attr_reader :links
|
15
|
+
|
16
|
+
# define_link_getter sets up an attribute getter that fetches from
|
17
|
+
# the associated link, if available
|
18
|
+
def self.define_link_getter(name)
|
19
|
+
define_method(name) do |opts = {}|
|
20
|
+
stored_value = instance_variable_get("@#{name}")
|
21
|
+
return stored_value unless stored_value.nil?
|
22
|
+
|
23
|
+
instance_variable_set("@#{name}", fetch_link(name, api_key: opts[:api_key]))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# attr_objects sets up an associated object that can be parsed from json
|
28
|
+
def self.attr_objects(hash)
|
29
|
+
hash.each do |name, klass|
|
30
|
+
define_link_getter(name)
|
31
|
+
define_method("#{name}=") do |obj|
|
32
|
+
instance_variable_set(
|
33
|
+
"@#{name}",
|
34
|
+
parse_object(obj, klass),
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# attr_collections sets up an associated list of objects that can be
|
41
|
+
# parsed from the json
|
42
|
+
def self.attr_collections(hash)
|
43
|
+
hash.each do |name, klass|
|
44
|
+
define_link_getter(name)
|
45
|
+
define_method("#{name}=") do |ary|
|
46
|
+
instance_variable_set(
|
47
|
+
"@#{name}",
|
48
|
+
parse_collection(ary, klass),
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.attr_timestamp_accessor(*attrs)
|
55
|
+
attrs.each do |name|
|
56
|
+
attr_reader(name)
|
57
|
+
define_method("#{name}=") { |value|
|
58
|
+
instance_variable_set("@#{name}", parse_timestamp(value))
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_attribute(key, value)
|
64
|
+
setter = "#{self.class.underscore(key)}="
|
65
|
+
send(setter, value) if respond_to?(setter)
|
66
|
+
end
|
67
|
+
|
68
|
+
def set_attributes(hash) # rubocop:disable Naming/AccessorMethodName
|
69
|
+
hash.each do |key, value|
|
70
|
+
set_attribute(key, value)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def fetch_link(name, api_key: nil, params: {})
|
75
|
+
link = links[name.to_sym]
|
76
|
+
raise UnknownLinkError, "Unknown link `#{name}` for #{self.class.singularize}" if link.nil?
|
77
|
+
|
78
|
+
link.fetch(api_key: api_key, params: params)
|
79
|
+
end
|
80
|
+
|
81
|
+
def _links=(hash)
|
82
|
+
@links = hash.each_with_object({}) { |(name, data), memo|
|
83
|
+
memo[name.to_sym] = Link.new(data)
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def _embedded=(hash)
|
88
|
+
set_attributes(hash)
|
89
|
+
end
|
90
|
+
|
91
|
+
def inspect
|
92
|
+
"#<#{self.class} #{[@id, @name || @display_name].join(" ")}>"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|