kounta_rest 0.1.7 → 0.2.4
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.md +67 -36
- data/lib/kounta/address.rb +14 -17
- data/lib/kounta/break.rb +6 -0
- data/lib/kounta/category.rb +12 -15
- data/lib/kounta/company.rb +59 -50
- data/lib/kounta/customer.rb +33 -32
- data/lib/kounta/errors.rb +8 -7
- data/lib/kounta/inventory.rb +5 -7
- data/lib/kounta/line.rb +18 -21
- data/lib/kounta/order.rb +45 -49
- data/lib/kounta/payment.rb +14 -17
- data/lib/kounta/person.rb +21 -24
- data/lib/kounta/price_list.rb +7 -9
- data/lib/kounta/product.rb +25 -27
- data/lib/kounta/register.rb +11 -14
- data/lib/kounta/resource.rb +105 -93
- data/lib/kounta/rest/client.rb +177 -79
- data/lib/kounta/shift.rb +25 -0
- data/lib/kounta/site.rb +46 -38
- data/lib/kounta/staff.rb +30 -0
- data/lib/kounta/tax.rb +7 -9
- data/lib/kounta/version.rb +1 -1
- data/lib/kounta/webhook.rb +16 -0
- data/lib/kounta.rb +42 -72
- metadata +77 -145
- data/.gitignore +0 -20
- data/.gitmodules +0 -3
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/console.rb +0 -14
- data/kounta.gemspec +0 -33
- data/spec/fixtures/address.json +0 -12
- data/spec/fixtures/addresses.json +0 -25
- data/spec/fixtures/base_price_list.json +0 -52
- data/spec/fixtures/categories.json +0 -217
- data/spec/fixtures/category.json +0 -11
- data/spec/fixtures/companies_me.json +0 -45
- data/spec/fixtures/customer.json +0 -39
- data/spec/fixtures/customers.json +0 -26
- data/spec/fixtures/inventory.json +0 -10
- data/spec/fixtures/line.json +0 -7
- data/spec/fixtures/order.json +0 -67
- data/spec/fixtures/orders.json +0 -134
- data/spec/fixtures/payment.json +0 -6
- data/spec/fixtures/people.json +0 -20
- data/spec/fixtures/person.json +0 -41
- data/spec/fixtures/price_list.json +0 -52
- data/spec/fixtures/price_lists.json +0 -12
- data/spec/fixtures/product.json +0 -25
- data/spec/fixtures/products.json +0 -119
- data/spec/fixtures/site.json +0 -6
- data/spec/fixtures/sites.json +0 -14
- data/spec/fixtures/tax.json +0 -7
- data/spec/fixtures/taxes.json +0 -16
- data/spec/helper.rb +0 -28
- data/spec/kounta/address_spec.rb +0 -11
- data/spec/kounta/category_spec.rb +0 -11
- data/spec/kounta/company_spec.rb +0 -24
- data/spec/kounta/customer_spec.rb +0 -15
- data/spec/kounta/kounta_spec.rb +0 -21
- data/spec/kounta/line_spec.rb +0 -14
- data/spec/kounta/order_spec.rb +0 -37
- data/spec/kounta/payment_spec.rb +0 -14
- data/spec/kounta/person_spec.rb +0 -15
- data/spec/kounta/product_spec.rb +0 -16
- data/spec/kounta/resource_spec.rb +0 -95
- data/spec/kounta/rest/client_spec.rb +0 -38
- data/spec/kounta/site_spec.rb +0 -11
- data/spec/support/endpoints.rb +0 -72
data/lib/kounta/price_list.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
module Kounta
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
2
|
+
class PriceList < Kounta::Resource
|
3
|
+
property :parent_id
|
4
|
+
property :name
|
5
|
+
property :products
|
6
|
+
coerce_key :products, Product
|
7
|
+
end
|
8
|
+
end
|
data/lib/kounta/product.rb
CHANGED
@@ -1,31 +1,29 @@
|
|
1
1
|
module Kounta
|
2
|
+
class Product < Kounta::Resource
|
3
|
+
property :company_id
|
4
|
+
property :code
|
5
|
+
property :barcode
|
6
|
+
property :stock
|
7
|
+
property :name
|
8
|
+
property :description
|
9
|
+
property :tags
|
10
|
+
property :image
|
11
|
+
property :unit_price
|
12
|
+
property :cost_price
|
13
|
+
property :taxes
|
14
|
+
property :sites
|
15
|
+
property :number
|
2
16
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
property :barcode
|
7
|
-
property :stock
|
8
|
-
property :name
|
9
|
-
property :description
|
10
|
-
property :tags
|
11
|
-
property :image
|
12
|
-
property :unit_price
|
13
|
-
property :cost_price
|
14
|
-
property :taxes
|
15
|
-
property :sites
|
16
|
-
property :number
|
17
|
+
has_many(:categories, Kounta::Category, { company_id: :company_id },
|
18
|
+
proc { |klass| { companies: klass.company_id, products: klass.id, categories: nil } })
|
19
|
+
coerce_key :taxes, Kounta::Tax
|
17
20
|
|
18
|
-
|
19
|
-
|
21
|
+
def tags_include?(name)
|
22
|
+
tags.any? { |s| s.casecmp(name).zero? }
|
23
|
+
end
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
{companies: company_id, products: id}
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
25
|
+
def resource_path
|
26
|
+
{ companies: company_id, products: id }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/kounta/register.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
module Kounta
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
2
|
+
class Register < Kounta::Resource
|
3
|
+
property :company_id
|
4
|
+
property :code
|
5
|
+
property :name
|
6
|
+
property :site_id
|
7
|
+
|
8
|
+
def resource_path
|
9
|
+
{ companies: company_id, registers: id }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/kounta/resource.rb
CHANGED
@@ -1,96 +1,108 @@
|
|
1
1
|
require 'hashie'
|
2
|
-
require_relative
|
2
|
+
require_relative 'rest/client'
|
3
3
|
|
4
4
|
module Kounta
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
5
|
+
class Resource < Hashie::Dash
|
6
|
+
include Hashie::Extensions::Dash::IndifferentAccess if defined?(Hashie::Extensions::Dash::IndifferentAccess)
|
7
|
+
include Hashie::Extensions::Coercion
|
8
|
+
|
9
|
+
attr_accessor :client
|
10
|
+
|
11
|
+
property :id
|
12
|
+
property :created_at
|
13
|
+
property :updated_at
|
14
|
+
|
15
|
+
def self.coerce(data)
|
16
|
+
if data.is_a? Array
|
17
|
+
data.map { |item| new(item) }
|
18
|
+
else
|
19
|
+
new(data)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.has_one(sym, klass, assignments, route) # rubocop:disable Naming/PredicateName
|
24
|
+
define_method(sym) do |item_id = nil, *args|
|
25
|
+
if item_id
|
26
|
+
assign_into(client.object_from_response(klass, :get, route.call(self, item_id), params: args[0]), self, assignments)
|
27
|
+
else
|
28
|
+
assign_into(klass.new, self, assignments)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.has_many(sym, klass, assignments, route) # rubocop:disable Naming/PredicateName
|
34
|
+
define_method(sym) do |has_many_params = nil, *args|
|
35
|
+
client.objects_from_response(klass, :get, route.call(self, has_many_params), params: args[0])
|
36
|
+
.map { |returned_klass| assign_into(returned_klass, self, assignments) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.has_many_in_time_range(sym, klass, assignments, route) # rubocop:disable Naming/PredicateName
|
41
|
+
define_method(sym) do |has_many_params = nil, *args|
|
42
|
+
client.objects_from_response_in_time_range(klass, :get, route.call(self, has_many_params), params: args[0])
|
43
|
+
.map { |returned_klass| assign_into(returned_klass, self, assignments) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(hash = {})
|
48
|
+
return unless hash
|
49
|
+
|
50
|
+
hash.each_pair do |k, v|
|
51
|
+
begin
|
52
|
+
self[k] = v if respond_to? k.to_sym
|
53
|
+
rescue NoMethodError
|
54
|
+
raise Kounta::Errors::UnknownResourceAttribute, "Unknown attribute: #{k} on resource #{self.class}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_hash(hash = {})
|
60
|
+
{}.tap do |returning|
|
61
|
+
self.class.properties.each do |property|
|
62
|
+
next if ignored_properties.include?(property)
|
63
|
+
returning[property] = self[property] if self[property]
|
64
|
+
end
|
65
|
+
end.merge(hash)
|
66
|
+
end
|
67
|
+
|
68
|
+
def save!
|
69
|
+
response = new? ? client.perform(resource_path, :post, body: to_hash) : client.perform(resource_path, :put, body: to_hash)
|
70
|
+
|
71
|
+
# automatically follow redirects to resources
|
72
|
+
response = client.perform(response.headers['location'], :get) if response.status == 201
|
73
|
+
|
74
|
+
response.parsed.each_pair do |k, v|
|
75
|
+
self[k] = v if respond_to? k.to_sym
|
76
|
+
end
|
77
|
+
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def delete!
|
82
|
+
return self if new?
|
83
|
+
response = client.perform(resource_path, :delete)
|
84
|
+
|
85
|
+
except!('id', 'created_at', 'updated_at') if response.status == 204
|
86
|
+
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
def new?
|
91
|
+
!id
|
92
|
+
end
|
93
|
+
|
94
|
+
def ignored_properties(array = [])
|
95
|
+
array + %i[created_at updated_at id company_id]
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def assign_into(klass, assigner, assignments)
|
101
|
+
klass.client = assigner.client
|
102
|
+
assignments.each_pair do |k, v|
|
103
|
+
klass[k] = assigner[v]
|
104
|
+
end
|
105
|
+
klass
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/kounta/rest/client.rb
CHANGED
@@ -3,82 +3,180 @@ require 'oj'
|
|
3
3
|
require 'faraday_middleware'
|
4
4
|
|
5
5
|
module Kounta
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
6
|
+
module REST
|
7
|
+
class Client
|
8
|
+
def initialize(**options)
|
9
|
+
@redirect_uri = options[:redirect_uri]
|
10
|
+
@consumer = options[:consumer]
|
11
|
+
@access_token = options[:access_token]
|
12
|
+
@refresh_token = options[:refresh_token]
|
13
|
+
@client = OAuth2::Client.new(
|
14
|
+
@consumer[:key], @consumer[:secret],
|
15
|
+
site: Kounta::SITE_URI,
|
16
|
+
authorize_url: Kounta::AUTHORIZATION_URI,
|
17
|
+
token_url: Kounta::TOKEN_URI
|
18
|
+
) do |faraday|
|
19
|
+
faraday.request :json
|
20
|
+
faraday.use Faraday::Request::UrlEncoded
|
21
|
+
faraday.use Faraday::Response::Logger if Kounta.enable_logging
|
22
|
+
faraday.adapter Faraday.default_adapter
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def authenticated?
|
27
|
+
@access_token.present?
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_access_code_url(params = {})
|
31
|
+
# Kounta's API seems to require the `state` param (can't find documentation on it anywhere)
|
32
|
+
# learn more about it: http://homakov.blogspot.com.au/2012/07/saferweb-most-common-oauth2.html
|
33
|
+
@client.auth_code.authorize_url(params.merge(redirect_uri: @redirect_uri, state: SecureRandom.hex(24)))
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_access_token(access_code)
|
37
|
+
@token = @client.auth_code.get_token(access_code, redirect_uri: @redirect_uri)
|
38
|
+
@access_token = @token.token
|
39
|
+
@expires_at = @token.expires_at
|
40
|
+
@refresh_token = @token.refresh_token
|
41
|
+
@token
|
42
|
+
end
|
43
|
+
|
44
|
+
def company(hash = {})
|
45
|
+
@company ||= Kounta::Company.new(self, hash)
|
46
|
+
end
|
47
|
+
|
48
|
+
def path_from_hash(url_hash)
|
49
|
+
# TODO: there's probably a more correct way of doing this encoding
|
50
|
+
url_hash.map { |key, value| value ? "#{key}/#{value.to_s.gsub('-', '%2D')}" : key.to_s }.join('/')
|
51
|
+
end
|
52
|
+
|
53
|
+
def perform(url_hash, request_method, options = {})
|
54
|
+
begin
|
55
|
+
response = if url_hash.is_a? Hash
|
56
|
+
oauth_connection.request(request_method, "#{path_from_hash(url_hash)}.#{FORMAT}", options)
|
57
|
+
else
|
58
|
+
oauth_connection.request(request_method, url_hash, options)
|
59
|
+
end
|
60
|
+
rescue Exception => ex # rubocop:disable Lint/RescueException
|
61
|
+
msg = ex.message
|
62
|
+
if !msg.nil? && (msg.include?('The access token provided has expired') || msg.include?('expired') || msg.include?('invalid'))
|
63
|
+
@oauth_connection = refreshed_token
|
64
|
+
retry
|
65
|
+
end
|
66
|
+
|
67
|
+
raise Kounta::Errors::RequestError, response.nil? ? 'Unknown Status' : response.status
|
68
|
+
end
|
69
|
+
|
70
|
+
raise Kounta::Errors::RequestError, 'Unknown Status' unless response
|
71
|
+
|
72
|
+
response
|
73
|
+
end
|
74
|
+
|
75
|
+
def objects_from_response(klass, request_method, url_hash, options = {})
|
76
|
+
response = perform(url_hash, request_method, options)
|
77
|
+
last_page = response.headers['x-pages'].to_i - 1
|
78
|
+
results = response.parsed
|
79
|
+
|
80
|
+
# Already got page 0, start at page 1
|
81
|
+
(1..last_page).each do |page_number|
|
82
|
+
response = perform(url_hash, request_method, options.merge!(headers: { 'X-Page' => page_number.to_s }))
|
83
|
+
results += response.parsed
|
84
|
+
end
|
85
|
+
|
86
|
+
results.map { |item| klass.new(item) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def object_from_response(klass, request_method, url_hash, options = {})
|
90
|
+
response = perform(url_hash, request_method, options)
|
91
|
+
klass.new(response.parsed)
|
92
|
+
end
|
93
|
+
|
94
|
+
def objects_from_response_in_time_range(klass, request_method, url_hash, options = {})
|
95
|
+
if options.key?(:params) && (options[:params].key?(:created_gte) ^ options[:params].key?(:created_gt)) &&
|
96
|
+
(options[:params].key?(:created_lte) ^ options[:params].key?(:created_lt))
|
97
|
+
params = options[:params]
|
98
|
+
start_equal = params.key?(:created_gte)
|
99
|
+
finish_equal = params.key?(:created_lte)
|
100
|
+
start = (start_equal ? params[:created_gte] : params[:created_gt]).to_time
|
101
|
+
finish = (finish_equal ? params[:created_lte] : params[:created_lt]).to_time
|
102
|
+
|
103
|
+
params.except!(:created_gte, :created_gt, :created_lte, :created_lt)
|
104
|
+
|
105
|
+
start_date = start.to_date
|
106
|
+
finish_date = finish.to_date
|
107
|
+
|
108
|
+
start = start.to_i
|
109
|
+
finish = finish.to_i
|
110
|
+
|
111
|
+
results = []
|
112
|
+
|
113
|
+
options[:params] = params.merge(created_gte: start_date, created_lte: finish_date)
|
114
|
+
response = perform(url_hash, request_method, options)
|
115
|
+
last_page = response.headers['x-pages'].to_i - 1
|
116
|
+
parsed = response.parsed.map do |o|
|
117
|
+
o['created_at_epoch'] = Time.parse(o['created_at']).to_i
|
118
|
+
o
|
119
|
+
end
|
120
|
+
|
121
|
+
response_start = parsed.last['created_at_epoch']
|
122
|
+
response_finish = parsed.first['created_at_epoch']
|
123
|
+
|
124
|
+
# all current and future responses will be before the required start
|
125
|
+
return results if response_finish < start
|
126
|
+
|
127
|
+
# reverse to order them in ascending order
|
128
|
+
results += filter_responses_in_date_range(parsed.reverse, start, finish)
|
129
|
+
|
130
|
+
# all future responses will be before the required start
|
131
|
+
return results if response_start < start
|
132
|
+
|
133
|
+
(1..last_page).each do |page_number|
|
134
|
+
response = perform(url_hash, request_method, options.merge!(headers: { 'X-Page' => page_number.to_s }))
|
135
|
+
parsed = response.parsed.map do |o|
|
136
|
+
o['created_at_epoch'] = Time.parse(o['created_at']).to_i
|
137
|
+
o
|
138
|
+
end
|
139
|
+
|
140
|
+
response_start = parsed.last['created_at_epoch']
|
141
|
+
response_finish = parsed.first['created_at_epoch']
|
142
|
+
|
143
|
+
# all current and future responses will be before the required start
|
144
|
+
break if response_finish < start
|
145
|
+
|
146
|
+
# reverse to order them in ascending order
|
147
|
+
results += filter_responses_in_date_range(parsed.reverse, start, finish)
|
148
|
+
|
149
|
+
# all future responses will be before the required start
|
150
|
+
break if response_start < start
|
151
|
+
end
|
152
|
+
|
153
|
+
# reverse to under reverses used to order them in ascending order
|
154
|
+
results.reverse.map { |item| klass.new(item) }
|
155
|
+
else
|
156
|
+
raise ArgumentError, 'url_has must contain exactly one of [:created_gte, :created_gt] ' \
|
157
|
+
'and exactly one of [:created_lte, :created_lt]'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def filter_responses_in_date_range(parsed_responses, start, finish)
|
162
|
+
start_index = parsed_responses.index { |response| response['created_at_epoch'] >= start } || parsed_responses.length - 1
|
163
|
+
finish_index = parsed_responses.rindex { |response| response['created_at_epoch'] <= finish } || 0
|
164
|
+
parsed_responses[start_index..finish_index]
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def oauth_connection
|
170
|
+
@oauth_connection ||= if @refresh_token
|
171
|
+
OAuth2::AccessToken.new(@client, @access_token, refresh_token: @refresh_token).refresh!
|
172
|
+
else
|
173
|
+
OAuth2::AccessToken.new(@client, @access_token)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def refreshed_token
|
178
|
+
OAuth2::AccessToken.from_hash(@client, refresh_token: @refresh_token).refresh!
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/lib/kounta/shift.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kounta
|
2
|
+
class Shift < Kounta::Resource
|
3
|
+
property :company_id
|
4
|
+
property :staff_member
|
5
|
+
property :site
|
6
|
+
property :started_at
|
7
|
+
property :finished_at
|
8
|
+
property :breaks
|
9
|
+
|
10
|
+
# coerce_key :staff_member, Kounta::Staff
|
11
|
+
# coerce_key :site, Kounta::Site
|
12
|
+
coerce_key :breaks, Kounta::Break
|
13
|
+
|
14
|
+
def initialize(hash = {})
|
15
|
+
super(hash)
|
16
|
+
self.breaks ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
returning = {}
|
21
|
+
returning[:breaks] = breaks.map(&:to_hash) if breaks && !breaks.empty?
|
22
|
+
super(returning)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|