fera-api 0.1.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.
- 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
|