fera-api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.idea/fera-api.iml +86 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +91 -0
- data/.rspec +3 -0
- data/.rubocop.yml +56 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +92 -0
- data/LICENSE.txt +21 -0
- data/README.md +256 -0
- data/Rakefile +12 -0
- data/lib/fera/api/version.rb +7 -0
- data/lib/fera/api.rb +69 -0
- data/lib/fera/app.rb +33 -0
- data/lib/fera/models/base.rb +374 -0
- data/lib/fera/models/collection.rb +26 -0
- data/lib/fera/models/concerns/belongs_to_customer.rb +70 -0
- data/lib/fera/models/concerns/belongs_to_order.rb +87 -0
- data/lib/fera/models/concerns/belongs_to_product.rb +48 -0
- data/lib/fera/models/concerns/belongs_to_review.rb +40 -0
- data/lib/fera/models/concerns/belongs_to_submission.rb +39 -0
- data/lib/fera/models/concerns/has_many_orders.rb +30 -0
- data/lib/fera/models/concerns/has_many_reviews.rb +30 -0
- data/lib/fera/models/concerns/has_many_submissions.rb +30 -0
- data/lib/fera/models/concerns/has_media.rb +95 -0
- data/lib/fera/models/concerns/has_subject.rb +44 -0
- data/lib/fera/models/customer.rb +8 -0
- data/lib/fera/models/media.rb +55 -0
- data/lib/fera/models/order.rb +5 -0
- data/lib/fera/models/photo.rb +5 -0
- data/lib/fera/models/product.rb +12 -0
- data/lib/fera/models/rating.rb +9 -0
- data/lib/fera/models/review.rb +18 -0
- data/lib/fera/models/store.rb +11 -0
- data/lib/fera/models/submission.rb +19 -0
- data/lib/fera/models/video.rb +5 -0
- data/lib/fera/models/webhook.rb +4 -0
- data/lib/fera.rb +4 -0
- metadata +167 -0
data/lib/fera/api.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'require_all'
|
2
|
+
|
3
|
+
require 'active_resource'
|
4
|
+
|
5
|
+
require_rel "./api/version"
|
6
|
+
require_rel "./api"
|
7
|
+
require_rel "./app"
|
8
|
+
require_rel "./models"
|
9
|
+
require_rel "./models/concerns"
|
10
|
+
|
11
|
+
module Fera
|
12
|
+
module API
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
DEFAULT_HEADERS = {
|
16
|
+
'Api-Client' => "fera_ruby_sdk-#{ API::VERSION }",
|
17
|
+
}
|
18
|
+
|
19
|
+
##
|
20
|
+
# @param api_key [String] Public API key, Secret API key or Auth Token (if app)
|
21
|
+
def self.configure(api_key, api_url: nil, strict_mode: false)
|
22
|
+
previous_base_site = Base.site
|
23
|
+
previous_base_headers = Base.headers
|
24
|
+
|
25
|
+
Base.site = api_url || 'https://api.fera.ai/v3/private'
|
26
|
+
|
27
|
+
if api_key =~ /^sk_/
|
28
|
+
Base.headers['Secret-Key'] = api_key
|
29
|
+
elsif api_key =~ /^pk_/
|
30
|
+
Base.headers['Public-Key'] = api_key
|
31
|
+
else
|
32
|
+
Base.headers['Authorization'] = "Bearer #{ api_key }"
|
33
|
+
end
|
34
|
+
|
35
|
+
Base.headers['Strict-Mode'] = strict_mode if strict_mode
|
36
|
+
|
37
|
+
if block_given?
|
38
|
+
begin
|
39
|
+
result = yield
|
40
|
+
ensure
|
41
|
+
Base.site = previous_base_site
|
42
|
+
previous_base_headers.each do |key, value|
|
43
|
+
Base.headers[key] = value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
result
|
48
|
+
else
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.revoke_token!(client_id:, client_secret:, auth_token:)
|
55
|
+
previous_site = Base.site
|
56
|
+
|
57
|
+
Base.site = "https://app.fera.ai"
|
58
|
+
|
59
|
+
body = { client_id: client_id, client_secret: client_secret, token: auth_token }
|
60
|
+
|
61
|
+
result = Base.connection.post("https://app.fera.ai/oauth/revoke", body.to_json)
|
62
|
+
|
63
|
+
Base.site = previous_site
|
64
|
+
|
65
|
+
result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
Fera::Api = Fera::API # @alias
|
data/lib/fera/app.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Fera
|
2
|
+
class App
|
3
|
+
def initialize(client_id, client_secret, options = {})
|
4
|
+
@client_id = client_id
|
5
|
+
@client_secret = client_secret
|
6
|
+
@options = options
|
7
|
+
|
8
|
+
@app_url = options[:app_url] || 'https://app.fera.ai'
|
9
|
+
@api_url = options[:api_url] || 'https://api.fera.ai'
|
10
|
+
end
|
11
|
+
|
12
|
+
def revoke_token!(auth_token)
|
13
|
+
previous_site = Base.site
|
14
|
+
|
15
|
+
Base.site = @app_url
|
16
|
+
|
17
|
+
body = { client_id: @client_id, client_secret: @client_secret, token: auth_token }
|
18
|
+
|
19
|
+
result = Base.connection.post("#{ @app_url }/oauth/revoke", body.to_json)
|
20
|
+
|
21
|
+
Base.site = previous_site
|
22
|
+
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def decode_jwt(jwt)
|
27
|
+
JWT.decode(jwt, @client_secret, true).try(:first).to_h.with_indifferent_access
|
28
|
+
rescue StandardError
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,374 @@
|
|
1
|
+
require_relative './collection'
|
2
|
+
|
3
|
+
module Fera
|
4
|
+
class Base < ActiveResource::Base
|
5
|
+
# include ActiveModel::Dirty
|
6
|
+
|
7
|
+
attr_reader :last_response, :last_response_body, :last_response_message, :last_response_exception, :options
|
8
|
+
|
9
|
+
self.collection_parser = ::Fera::Collection
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def belongs_to(name, options = {})
|
13
|
+
@belongs_tos = @belongs_tos.to_h.merge(name => options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def belongs_tos; @belongs_tos.to_h; end
|
17
|
+
|
18
|
+
def has_many(name, options = {})
|
19
|
+
@has_manys = @has_manys.to_h.merge(name => options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_manys; @has_manys.to_h; end
|
23
|
+
|
24
|
+
def has_one(name, options = {})
|
25
|
+
@has_ones = @has_ones.to_h.merge(name => options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_ones; @has_ones.to_h; end
|
29
|
+
|
30
|
+
def headers
|
31
|
+
if _headers_defined?
|
32
|
+
_headers
|
33
|
+
elsif superclass != Object && superclass.headers
|
34
|
+
superclass.headers
|
35
|
+
else
|
36
|
+
_headers ||= {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_params=(default_params)
|
41
|
+
@default_params = default_params
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# @override to support extra_params
|
46
|
+
def create(attributes = {}, extra_params = {})
|
47
|
+
self.new(attributes, false).tap { |resource| resource.create(extra_params) }
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# @override to fix issue that it's not raising the error and also to support extra_params
|
52
|
+
def create!(attributes = {}, extra_params = {})
|
53
|
+
self.new(attributes, false).tap { |resource| resource.create!(extra_params) }
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @override to support default params
|
58
|
+
def find_every(options)
|
59
|
+
super(add_default_params(options))
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# @override to support default params
|
64
|
+
def find_one(options)
|
65
|
+
super(add_default_params(options))
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# @override to support default params
|
70
|
+
def find_single(scope, options)
|
71
|
+
options = add_default_params(options)
|
72
|
+
prefix_options, query_options = split_options(options[:params])
|
73
|
+
path = element_path(scope, prefix_options, query_options)
|
74
|
+
|
75
|
+
response = connection.get(path, headers)
|
76
|
+
record = instantiate_record(format.decode(response.body), prefix_options)
|
77
|
+
|
78
|
+
record.set_last_response(response)
|
79
|
+
record
|
80
|
+
end
|
81
|
+
|
82
|
+
def new_element_path(prefix_options = {}, extra_params = {})
|
83
|
+
url = "#{prefix(prefix_options)}#{collection_name}/new#{format_extension}"
|
84
|
+
url += "?#{ extra_params.to_param }" if extra_params.present?
|
85
|
+
url
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def add_default_params(options)
|
91
|
+
if @default_params.present?
|
92
|
+
options ||= {}
|
93
|
+
options[:params] = options[:params].to_h.merge(@default_params)
|
94
|
+
end
|
95
|
+
|
96
|
+
options
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def initialize(attributes = nil, persisted = nil, options = {})
|
101
|
+
@options = options.to_h
|
102
|
+
|
103
|
+
dynamic_attributes = attributes.to_h.dup
|
104
|
+
|
105
|
+
association_keys = self.class.has_manys.keys + self.class.has_ones.keys + self.class.belongs_tos.keys
|
106
|
+
|
107
|
+
dynamic_attributes.except!(*(association_keys + association_keys.map(&:to_s)))
|
108
|
+
|
109
|
+
super(dynamic_attributes, persisted)
|
110
|
+
|
111
|
+
association_keys.each do |name, opts|
|
112
|
+
if attributes.key?(name.to_s) || attributes.key?(name.to_sym)
|
113
|
+
val = attributes.to_h[name.to_s] || attributes.to_h[name.to_sym]
|
114
|
+
self.send("#{ name }=", val) if respond_to?("#{ name }=")
|
115
|
+
end
|
116
|
+
end if attributes.present?
|
117
|
+
end
|
118
|
+
|
119
|
+
def load(attributes, *args)
|
120
|
+
load_result = super(attributes, *args)
|
121
|
+
|
122
|
+
attributes.each do |attr, val|
|
123
|
+
if respond_to?("#{ attr }=".to_sym)
|
124
|
+
self.send("#{ attr }=".to_sym, val)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
@clean_copy = clone_with_nil if persisted? && !options[:cloned]
|
129
|
+
|
130
|
+
load_result
|
131
|
+
end
|
132
|
+
|
133
|
+
def destroy!
|
134
|
+
destroy
|
135
|
+
end
|
136
|
+
|
137
|
+
def created_at=(new_created_at)
|
138
|
+
return super(Time.parse(new_created_at)) if new_created_at.is_a?(String)
|
139
|
+
super
|
140
|
+
end
|
141
|
+
|
142
|
+
def updated_at=(new_updated_at)
|
143
|
+
return super(Time.parse(new_updated_at)) if new_updated_at.is_a?(String)
|
144
|
+
super
|
145
|
+
end
|
146
|
+
|
147
|
+
def update(changed_attributes, extra_params = {}, raise = false)
|
148
|
+
run_callbacks(:update) do
|
149
|
+
connection.put(element_path(prefix_options, extra_params), dynamic_changed_attributes.to_json, self.class.headers).tap do |response|
|
150
|
+
load_attributes_from_response(response)
|
151
|
+
end
|
152
|
+
|
153
|
+
load(changed_attributes)
|
154
|
+
end
|
155
|
+
|
156
|
+
true
|
157
|
+
rescue ActiveResource::ConnectionError => e
|
158
|
+
set_last_response(e)
|
159
|
+
|
160
|
+
if raise
|
161
|
+
raise(ActiveResource::ResourceInvalid.new(last_response, last_response_message.presence))
|
162
|
+
end
|
163
|
+
|
164
|
+
false
|
165
|
+
end
|
166
|
+
|
167
|
+
def update!(changed_attributes, extra_params = {})
|
168
|
+
update(changed_attributes, extra_params, true)
|
169
|
+
end
|
170
|
+
|
171
|
+
def valid?(context = nil)
|
172
|
+
super()
|
173
|
+
end
|
174
|
+
|
175
|
+
##
|
176
|
+
# @override to add exgtra params
|
177
|
+
def create(extra_params = {}, raise = false)
|
178
|
+
run_callbacks :create do
|
179
|
+
|
180
|
+
data = as_json
|
181
|
+
(self.class.belongs_tos.merge(self.class.has_ones)).each do |name, opts|
|
182
|
+
next unless instance_variable_defined?(:"@#{ name }")
|
183
|
+
nested_resource = self.send(name)
|
184
|
+
if nested_resource.present? && !nested_resource.persisted?
|
185
|
+
nested_resource.validate!
|
186
|
+
data[name] = nested_resource.as_json
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
self.class.has_manys.each do |name, opts|
|
191
|
+
next unless instance_variable_defined?(:"@#{ name }")
|
192
|
+
nested_resource = self.send(name)
|
193
|
+
|
194
|
+
next if nested_resource.nil?
|
195
|
+
|
196
|
+
nested_resource.each do |nested_resource_instance|
|
197
|
+
next if nested_resource_instance.persisted?
|
198
|
+
|
199
|
+
nested_resource_instance.validate!
|
200
|
+
|
201
|
+
data[name] ||= []
|
202
|
+
data[name] << nested_resource_instance.as_json
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
connection.post(collection_path(nil, extra_params), data.to_json, self.class.headers).tap do |response|
|
207
|
+
self.id = id_from_response(response)
|
208
|
+
load_attributes_from_response(response)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
true
|
213
|
+
rescue ActiveResource::ConnectionError => e
|
214
|
+
set_last_response(e)
|
215
|
+
|
216
|
+
if raise
|
217
|
+
raise(ActiveResource::ResourceInvalid.new(last_response, last_response_message.presence))
|
218
|
+
end
|
219
|
+
|
220
|
+
false
|
221
|
+
end
|
222
|
+
|
223
|
+
def create!(extra_params = {})
|
224
|
+
create(extra_params, true)
|
225
|
+
end
|
226
|
+
|
227
|
+
def save(extra_params = {}, raise = false)
|
228
|
+
run_callbacks :save do
|
229
|
+
if new?
|
230
|
+
create(extra_params, raise) # We'll raise the error below
|
231
|
+
else
|
232
|
+
# find changes
|
233
|
+
changed_attributes = attributes.filter { |key, value| !@clean_copy.attributes.key?(key) || (@clean_copy.attributes[key] != value) || (key == self.class.primary_key) }
|
234
|
+
changed_attributes.reject! { |k| k == 'id' }
|
235
|
+
return false unless changed_attributes.keys.any?
|
236
|
+
|
237
|
+
# save
|
238
|
+
update(changed_attributes, extra_params, raise)
|
239
|
+
end
|
240
|
+
|
241
|
+
@clean_copy = clone_with_nil # Clear changes
|
242
|
+
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
def save!(extra_params = {})
|
249
|
+
save(extra_params, true)
|
250
|
+
end
|
251
|
+
|
252
|
+
def clone_with_nil
|
253
|
+
# Clone all attributes except the pk and any nested ARes
|
254
|
+
cloned = Hash[attributes.reject { |k, v| k == self.class.primary_key || v.is_a?(ActiveResource::Base) }.map { |k, v| [k, v.clone] }]
|
255
|
+
# Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
|
256
|
+
# attempts to convert hashes into member objects and arrays into collections of objects. We want
|
257
|
+
# the raw objects to be cloned so we bypass load by directly setting the attributes hash.
|
258
|
+
resource = self.class.new({}, true, { cloned: true })
|
259
|
+
resource.prefix_options = prefix_options
|
260
|
+
resource.send :instance_variable_set, '@attributes', cloned
|
261
|
+
resource
|
262
|
+
end
|
263
|
+
|
264
|
+
def clone_selected_fields(model, fields)
|
265
|
+
fields = fields.is_a?(Array) ? fields : fields.to_s.split(',').map(&:strip)
|
266
|
+
|
267
|
+
# find fields
|
268
|
+
changed_attributes = HashWithIndifferentAccess.new
|
269
|
+
changed_attributes[model.class.primary_key] = model.attributes[model.class.primary_key]
|
270
|
+
fields.each do |key|
|
271
|
+
if key.include?(':')
|
272
|
+
clone_sub_fields(model, key, changed_attributes)
|
273
|
+
elsif fields.include?(key)
|
274
|
+
changed_attributes[key] = model.attributes[key]
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# create new object
|
279
|
+
self.class.new(changed_attributes, true)
|
280
|
+
end
|
281
|
+
|
282
|
+
#
|
283
|
+
# Method missing adapters to define public_*_id
|
284
|
+
#
|
285
|
+
|
286
|
+
def method_missing(method_name, *args, &block)
|
287
|
+
matcher = method_name.to_s.match(/^(?!is_)([a-z_]+)\?$/) || method_name.to_s.match(/^is_([a-z_]+)\?$/)
|
288
|
+
if matcher.present?
|
289
|
+
attribute_name = matcher[1]
|
290
|
+
return super if attribute_name.blank?
|
291
|
+
attribute_name = "is_#{ attribute_name }" unless attribute_name =~ /^is_/
|
292
|
+
return super unless known_attribute?(attribute_name.to_s)
|
293
|
+
return !!(send(attribute_name.to_sym).presence)
|
294
|
+
end
|
295
|
+
|
296
|
+
super
|
297
|
+
end
|
298
|
+
|
299
|
+
def respond_to_missing?(method_name, include_private = false)
|
300
|
+
matcher = method_name.to_s.match(/^(?!is_)([a-z_]+)\?$/) || method_name.to_s.match(/^is_([a-z_]+)\?$/)
|
301
|
+
if matcher.present?
|
302
|
+
attribute_name = matcher[1]
|
303
|
+
return super if attribute_name.blank?
|
304
|
+
attribute_name = "is_#{ attribute_name }" unless attribute_name =~ /^is_/
|
305
|
+
return true if known_attribute?(attribute_name)
|
306
|
+
end
|
307
|
+
|
308
|
+
super
|
309
|
+
end
|
310
|
+
|
311
|
+
def known_attribute?(attribute_name)
|
312
|
+
known_attributes.map(&:to_s).include?(attribute_name.to_s)
|
313
|
+
end
|
314
|
+
|
315
|
+
def set_last_response(result)
|
316
|
+
response = if result.is_a?(StandardError)
|
317
|
+
@last_response_exception = result
|
318
|
+
@last_response_exception.response
|
319
|
+
else
|
320
|
+
@last_response_exception = nil
|
321
|
+
result
|
322
|
+
end
|
323
|
+
|
324
|
+
@last_response = response
|
325
|
+
@last_response_body = response.body.present? ? self.class.format.decode(response.body) : nil
|
326
|
+
@last_response_message = last_response_body.to_h['message']
|
327
|
+
end
|
328
|
+
|
329
|
+
protected
|
330
|
+
|
331
|
+
def load_attributes_from_response(response)
|
332
|
+
set_last_response(response)
|
333
|
+
super(response)
|
334
|
+
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
def new_has_many_associated_model(model_class, input = nil)
|
339
|
+
model = if input.blank? || input.is_a?(Hash)
|
340
|
+
model_class.new(input.to_h.with_indifferent_access, false)
|
341
|
+
else
|
342
|
+
model_class.instantiate_record(input, input.id.present?)
|
343
|
+
end
|
344
|
+
model.send("#{ self.class.name.demodulize.underscore }=", self)
|
345
|
+
model
|
346
|
+
end
|
347
|
+
|
348
|
+
def element_path(options = nil, extra_params = {})
|
349
|
+
self.class.element_path(to_param, options || prefix_options, extra_params)
|
350
|
+
end
|
351
|
+
|
352
|
+
def element_url(options = nil, extra_params = {})
|
353
|
+
self.class.element_url(to_param, options || prefix_options, extra_params)
|
354
|
+
end
|
355
|
+
|
356
|
+
def new_element_path(extra_params = {})
|
357
|
+
self.class.new_element_path(prefix_options, extra_params)
|
358
|
+
end
|
359
|
+
|
360
|
+
##
|
361
|
+
# @override
|
362
|
+
def collection_path(options = nil, extra_params = {})
|
363
|
+
self.class.collection_path(options || prefix_options, extra_params)
|
364
|
+
end
|
365
|
+
|
366
|
+
def clone_sub_fields(model, key, changed_attributes)
|
367
|
+
sub_fields = key.split(':')
|
368
|
+
sub_key = sub_fields.first
|
369
|
+
values = model.attributes[sub_key]
|
370
|
+
sub_fields = sub_fields.drop(1)
|
371
|
+
changed_attributes[sub_key] = values.map { |value| clone_selected_fields(value, sub_fields) }
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_resource/collection'
|
2
|
+
|
3
|
+
module Fera
|
4
|
+
class Collection < ActiveResource::Collection
|
5
|
+
attr_reader :result_count, :total_count, :page, :total_pages, :page_size, :offset, :limit
|
6
|
+
|
7
|
+
def initialize(parsed = {})
|
8
|
+
@elements = parsed['data']
|
9
|
+
@result_count = parsed['result_count']
|
10
|
+
@total_count = parsed['total_count']
|
11
|
+
|
12
|
+
@using_pagination = parsed.key?('page')
|
13
|
+
|
14
|
+
if @using_pagination
|
15
|
+
@page = parsed['page']
|
16
|
+
@total_pages = parsed['total_pages']
|
17
|
+
@page_size = parsed['page_size']
|
18
|
+
else
|
19
|
+
@offset = parsed['offset']
|
20
|
+
@limit = parsed['limit']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def using_pagination?; @using_pagination; end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Fera
|
4
|
+
module BelongsToCustomer
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
belongs_to :customer, class_name: "Fera::Customer"
|
9
|
+
end
|
10
|
+
|
11
|
+
def customer=(customer)
|
12
|
+
if customer.is_a?(Customer)
|
13
|
+
@customer = customer
|
14
|
+
self.attributes['customer_id'] = customer.id
|
15
|
+
self.attributes['external_customer_id'] = customer.try(:external_id)
|
16
|
+
self.attributes.delete('customer')
|
17
|
+
elsif customer.is_a?(Hash)
|
18
|
+
customer_id = customer.with_indifferent_access[:id]
|
19
|
+
|
20
|
+
if customer.with_indifferent_access.key?(:id) # Hash
|
21
|
+
if customer_id =~ /^fcus_/
|
22
|
+
self.attributes['customer_id'] = customer_id
|
23
|
+
else
|
24
|
+
self.attributes['external_customer_id'] = customer_id
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if customer.with_indifferent_access.key?(:external_id) # Hash
|
29
|
+
self.attributes['external_customer_id'] = customer.with_indifferent_access[:external_id]
|
30
|
+
end
|
31
|
+
|
32
|
+
@customer = Customer.new(customer, customer_id.present?)
|
33
|
+
self.attributes.delete('customer')
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
@customer
|
38
|
+
end
|
39
|
+
|
40
|
+
def customer_id=(new_id)
|
41
|
+
if @customer.present?
|
42
|
+
@customer.id = new_id
|
43
|
+
end
|
44
|
+
|
45
|
+
self.attributes['customer_id'] = new_id
|
46
|
+
end
|
47
|
+
|
48
|
+
def external_customer_id=(new_external_id)
|
49
|
+
if @customer.present?
|
50
|
+
@customer.external_id = new_external_id
|
51
|
+
end
|
52
|
+
|
53
|
+
self.attributes['external_customer_id'] = new_external_id
|
54
|
+
end
|
55
|
+
|
56
|
+
def customer
|
57
|
+
if @customer.present?
|
58
|
+
@customer
|
59
|
+
elsif attributes.key?('customer') && attributes['customer'].present?
|
60
|
+
Customer.new(attributes['customer'], true)
|
61
|
+
elsif attributes.key?('customer_id') && customer_id.present?
|
62
|
+
Customer.find(customer_id)
|
63
|
+
elsif attributes.key?('external_customer_id') && external_customer_id.present?
|
64
|
+
Customer.find(external_customer_id)
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Fera
|
4
|
+
module BelongsToOrder
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
belongs_to :order, class_name: "Fera::Order"
|
9
|
+
end
|
10
|
+
|
11
|
+
def order=(order)
|
12
|
+
order_id = if order.is_a?(Order)
|
13
|
+
order.id
|
14
|
+
else
|
15
|
+
order.try(:with_indifferent_access).try(:[], :id)
|
16
|
+
end
|
17
|
+
external_order_id = if order.is_a?(Order)
|
18
|
+
order.external_id
|
19
|
+
else
|
20
|
+
order.try(:with_indifferent_access).try(:[], :external_id)
|
21
|
+
end
|
22
|
+
@order = if order.is_a?(Order)
|
23
|
+
order
|
24
|
+
else
|
25
|
+
Order.new(order, order_id.present?)
|
26
|
+
end
|
27
|
+
self.attributes['order_id'] = order_id
|
28
|
+
self.attributes['external_order_id'] = external_order_id
|
29
|
+
self.attributes.delete('order')
|
30
|
+
@order
|
31
|
+
end
|
32
|
+
|
33
|
+
def order_id=(new_id)
|
34
|
+
return new_id if order_id == new_id
|
35
|
+
|
36
|
+
if new_id.nil?
|
37
|
+
reset_order_instance_assoc
|
38
|
+
else
|
39
|
+
self.attributes['order_id'] = new_id
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def external_order_id=(new_id)
|
44
|
+
return new_id if external_order_id == new_id
|
45
|
+
|
46
|
+
if new_id.nil?
|
47
|
+
reset_order_instance_assoc
|
48
|
+
else
|
49
|
+
self.attributes['external_order_id'] = new_id
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def order
|
54
|
+
if @order.present?
|
55
|
+
@order
|
56
|
+
else
|
57
|
+
load_order
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def reload
|
62
|
+
reset_order_instance_assoc
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def reset_order_instance_assoc
|
69
|
+
remove_instance_variable(:@order)
|
70
|
+
self.attributes['order_id'] = nil
|
71
|
+
self.attributes['external_order_id'] = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_order
|
75
|
+
if attributes.key?('order') && attributes['order'].present?
|
76
|
+
Order.new(attributes['order'], true)
|
77
|
+
elsif attributes.key?('order_id') && order_id.present?
|
78
|
+
Order.find(order_id)
|
79
|
+
elsif attributes.key?('external_order_id') && external_order_id.present?
|
80
|
+
Order.find(external_order_id)
|
81
|
+
else
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|