gecko-ruby 0.0.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 +7 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +9 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +41 -0
- data/CONTRIBUTING.md +0 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +144 -0
- data/Rakefile +19 -0
- data/gecko-ruby.gemspec +34 -0
- data/generate.thor +81 -0
- data/lib/gecko-ruby.rb +1 -0
- data/lib/gecko.rb +31 -0
- data/lib/gecko/client.rb +132 -0
- data/lib/gecko/helpers/association_helper.rb +69 -0
- data/lib/gecko/helpers/inspection_helper.rb +51 -0
- data/lib/gecko/helpers/record_helper.rb +29 -0
- data/lib/gecko/helpers/serialization_helper.rb +61 -0
- data/lib/gecko/helpers/validation_helper.rb +91 -0
- data/lib/gecko/record/account.rb +66 -0
- data/lib/gecko/record/address.rb +33 -0
- data/lib/gecko/record/base.rb +66 -0
- data/lib/gecko/record/base_adapter.rb +365 -0
- data/lib/gecko/record/company.rb +41 -0
- data/lib/gecko/record/contact.rb +25 -0
- data/lib/gecko/record/currency.rb +23 -0
- data/lib/gecko/record/exceptions.rb +15 -0
- data/lib/gecko/record/fulfillment.rb +42 -0
- data/lib/gecko/record/fulfillment_line_item.rb +26 -0
- data/lib/gecko/record/image.rb +38 -0
- data/lib/gecko/record/invoice.rb +29 -0
- data/lib/gecko/record/invoice_line_item.rb +18 -0
- data/lib/gecko/record/location.rb +23 -0
- data/lib/gecko/record/order.rb +50 -0
- data/lib/gecko/record/order_line_item.rb +35 -0
- data/lib/gecko/record/product.rb +27 -0
- data/lib/gecko/record/purchase_order.rb +43 -0
- data/lib/gecko/record/purchase_order_line_item.rb +29 -0
- data/lib/gecko/record/tax_type.rb +21 -0
- data/lib/gecko/record/user.rb +44 -0
- data/lib/gecko/record/variant.rb +96 -0
- data/lib/gecko/version.rb +3 -0
- data/test/client_test.rb +29 -0
- data/test/fixtures/vcr_cassettes/accounts.yml +57 -0
- data/test/fixtures/vcr_cassettes/accounts_current.yml +57 -0
- data/test/fixtures/vcr_cassettes/addresses.yml +68 -0
- data/test/fixtures/vcr_cassettes/addresses_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/companies.yml +62 -0
- data/test/fixtures/vcr_cassettes/companies_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/contacts.yml +60 -0
- data/test/fixtures/vcr_cassettes/contacts_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/currencies.yml +62 -0
- data/test/fixtures/vcr_cassettes/currencies_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/fulfillments.yml +59 -0
- data/test/fixtures/vcr_cassettes/fulfillments_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/images.yml +59 -0
- data/test/fixtures/vcr_cassettes/images_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/invoice_line_items.yml +63 -0
- data/test/fixtures/vcr_cassettes/invoice_line_items_count.yml +62 -0
- data/test/fixtures/vcr_cassettes/invoices.yml +63 -0
- data/test/fixtures/vcr_cassettes/invoices_count.yml +62 -0
- data/test/fixtures/vcr_cassettes/locations.yml +65 -0
- data/test/fixtures/vcr_cassettes/locations_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/order_line_items.yml +63 -0
- data/test/fixtures/vcr_cassettes/order_line_items_count.yml +62 -0
- data/test/fixtures/vcr_cassettes/orders.yml +62 -0
- data/test/fixtures/vcr_cassettes/orders_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/products.yml +79 -0
- data/test/fixtures/vcr_cassettes/products_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/products_new_invalid.yml +54 -0
- data/test/fixtures/vcr_cassettes/products_new_valid.yml +58 -0
- data/test/fixtures/vcr_cassettes/purchase_order_line_items.yml +64 -0
- data/test/fixtures/vcr_cassettes/purchase_order_line_items_count.yml +62 -0
- data/test/fixtures/vcr_cassettes/purchase_orders.yml +63 -0
- data/test/fixtures/vcr_cassettes/purchase_orders_count.yml +62 -0
- data/test/fixtures/vcr_cassettes/tax_types.yml +74 -0
- data/test/fixtures/vcr_cassettes/tax_types_count.yml +62 -0
- data/test/fixtures/vcr_cassettes/users.yml +60 -0
- data/test/fixtures/vcr_cassettes/users_count.yml +58 -0
- data/test/fixtures/vcr_cassettes/users_current.yml +54 -0
- data/test/fixtures/vcr_cassettes/variants.yml +60 -0
- data/test/fixtures/vcr_cassettes/variants_count.yml +58 -0
- data/test/gecko_test.rb +7 -0
- data/test/helpers/association_helper_test.rb +56 -0
- data/test/helpers/inspection_helper_test.rb +27 -0
- data/test/helpers/serialization_helper_test.rb +30 -0
- data/test/helpers/validation_helper_test.rb +24 -0
- data/test/record/account_adapter_test.rb +43 -0
- data/test/record/address_adapter_test.rb +14 -0
- data/test/record/address_test.rb +18 -0
- data/test/record/company_adapter_test.rb +14 -0
- data/test/record/company_test.rb +18 -0
- data/test/record/contact_adapter_test.rb +14 -0
- data/test/record/contact_test.rb +18 -0
- data/test/record/currency_adapter_test.rb +14 -0
- data/test/record/currency_test.rb +18 -0
- data/test/record/fulfillment_adapter_test.rb +24 -0
- data/test/record/fulfillment_line_item_adapter_test.rb +21 -0
- data/test/record/fulfillment_line_item_test.rb +18 -0
- data/test/record/fulfillment_test.rb +27 -0
- data/test/record/image_adapter_test.rb +14 -0
- data/test/record/image_test.rb +25 -0
- data/test/record/invoice_adapter_test.rb +14 -0
- data/test/record/invoice_line_item_adapter_test.rb +20 -0
- data/test/record/invoice_line_item_test.rb +18 -0
- data/test/record/invoice_test.rb +18 -0
- data/test/record/location_adapter_test.rb +14 -0
- data/test/record/location_test.rb +18 -0
- data/test/record/order_adapter_test.rb +14 -0
- data/test/record/order_line_item_adapter_test.rb +14 -0
- data/test/record/order_line_item_test.rb +18 -0
- data/test/record/order_test.rb +18 -0
- data/test/record/product_adapter_test.rb +32 -0
- data/test/record/product_test.rb +18 -0
- data/test/record/purchase_order_adapter_test.rb +14 -0
- data/test/record/purchase_order_line_item_adapter_test.rb +14 -0
- data/test/record/purchase_order_line_item_test.rb +18 -0
- data/test/record/purchase_order_test.rb +18 -0
- data/test/record/tax_type_adapter_test.rb +14 -0
- data/test/record/tax_type_test.rb +18 -0
- data/test/record/user_adapter_test.rb +27 -0
- data/test/record/user_test.rb +18 -0
- data/test/record/variant_adapter_test.rb +14 -0
- data/test/record/variant_test.rb +44 -0
- data/test/support/let.rb +10 -0
- data/test/support/shared_adapter_examples.rb +159 -0
- data/test/support/shared_record_examples.rb +21 -0
- data/test/support/testing_adapter.rb +11 -0
- data/test/support/vcr_support.rb +7 -0
- data/test/test_helper.rb +21 -0
- metadata +430 -0
@@ -0,0 +1,365 @@
|
|
1
|
+
module Gecko
|
2
|
+
module Record
|
3
|
+
class BaseAdapter
|
4
|
+
attr_reader :client
|
5
|
+
# Instantiates a new Record Adapter
|
6
|
+
#
|
7
|
+
# @param [Gecko::Client] client
|
8
|
+
# @param [String] model_name
|
9
|
+
#
|
10
|
+
# @return [undefined]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def initialize(client, model_name)
|
14
|
+
@client = client
|
15
|
+
@model_name = model_name
|
16
|
+
@identity_map = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Find a record via ID, first searches the Identity Map, then makes an
|
20
|
+
# API request.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# client.Product.find(12)
|
24
|
+
#
|
25
|
+
# @param [Integer] id ID of record
|
26
|
+
#
|
27
|
+
# @return [Gecko::Record::Base] if a record was found
|
28
|
+
# either in the identity map or via the API
|
29
|
+
# @return [nil] If no record was found
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
def find(id)
|
33
|
+
if has_record_for_id?(id)
|
34
|
+
record_for_id(id)
|
35
|
+
else
|
36
|
+
fetch(id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Searches the Identity Map for a record via ID
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# client.Product.record_for_id(12)
|
44
|
+
#
|
45
|
+
# @return [Gecko::Record::Base] if a record was found in the identity map.
|
46
|
+
# @raise [Gecko::Record::RecordNotInIdentityMap] If no record was found
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
def record_for_id(id)
|
50
|
+
verify_id_presence!(id)
|
51
|
+
@identity_map.fetch(id) { record_not_in_identity_map!(id) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns whether the Identity Map has a record for a particular ID
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# client.Product.has_record_for_id?(12)
|
58
|
+
#
|
59
|
+
# @return [Boolean] if a record was found in the identity map.
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
def has_record_for_id?(id)
|
63
|
+
@identity_map.key?(id)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Find multiple records via IDs, searching the Identity Map, then making an
|
67
|
+
# API request for remaining records. May return nulls
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# client.Product.find_many([12, 13, 14])
|
71
|
+
#
|
72
|
+
# @param [Array<Integer>] ids IDs of records to fetch
|
73
|
+
#
|
74
|
+
# @return [Array<Gecko::Record::Base>] Records for the ids
|
75
|
+
# either in the identity map or via the API
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
def find_many(ids)
|
79
|
+
existing, required = ids.partition { |id| has_record_for_id?(id) }
|
80
|
+
if required.any?
|
81
|
+
where(ids: ids) + existing.map { |id| record_for_id(id) }
|
82
|
+
else
|
83
|
+
existing.map { |id| record_for_id(id) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Make an API request with parameters. Parameters vary via Record Type
|
88
|
+
#
|
89
|
+
# @example Fetch via ID
|
90
|
+
# client.Product.where(ids: [1,2]
|
91
|
+
#
|
92
|
+
# @example Fetch via date
|
93
|
+
# client.Product.where(updated_at_min: "2014-03-03T21:09:00")
|
94
|
+
#
|
95
|
+
# @example Search
|
96
|
+
# client.Product.where(q: "gecko")
|
97
|
+
#
|
98
|
+
# @param [#to_hash] params
|
99
|
+
# @option params [String] :q Search query
|
100
|
+
# @option params [Integer] :page (1) Page number for pagination
|
101
|
+
# @option params [Integer] :limit (100) Page limit for pagination
|
102
|
+
# @option params [Array<Integer>] :ids IDs to search for
|
103
|
+
# @option params [String] :updated_at_min Last updated_at minimum
|
104
|
+
# @option params [String] :updated_at_max Last updated_at maximum
|
105
|
+
# @option params [String] :order Sort order i.e 'name asc'
|
106
|
+
# @option params [String, Array<String>] :status Record status/es
|
107
|
+
#
|
108
|
+
# @return [Array<Gecko::Record::Base>] Records via the API
|
109
|
+
#
|
110
|
+
# @api public
|
111
|
+
def where(params={})
|
112
|
+
response = request(:get, plural_path, params: params)
|
113
|
+
parsed_response = response.parsed
|
114
|
+
set_pagination(response.headers)
|
115
|
+
parse_records(parsed_response)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Return total count for a record type. Fetched from the metadata
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# client.Product.count
|
122
|
+
#
|
123
|
+
# @return [Integer] Total record count
|
124
|
+
#
|
125
|
+
# @api public
|
126
|
+
def count
|
127
|
+
self.where(limit: 0)
|
128
|
+
@pagination['total_records']
|
129
|
+
end
|
130
|
+
|
131
|
+
# Fetch a record via API, regardless of whether it is already in identity map.
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# client.Product.fetch(12)
|
135
|
+
#
|
136
|
+
# @return [Gecko::Record::Base] if a record was found
|
137
|
+
# @return [nil] if no record was found
|
138
|
+
#
|
139
|
+
# @api private
|
140
|
+
def fetch(id)
|
141
|
+
verify_id_presence!(id)
|
142
|
+
response = request(:get, plural_path + '/' + id.to_s)
|
143
|
+
record_json = extract_record(response.parsed)
|
144
|
+
instantiate_and_register_record(record_json)
|
145
|
+
rescue OAuth2::Error => ex
|
146
|
+
case ex.response.status
|
147
|
+
when 404
|
148
|
+
record_not_found!(id)
|
149
|
+
else
|
150
|
+
raise
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Parse a json collection and instantiate records
|
155
|
+
#
|
156
|
+
# @return [Array<Gecko::Record::Base>]
|
157
|
+
#
|
158
|
+
# @api private
|
159
|
+
def parse_records(json)
|
160
|
+
extract_collection(json).map do |record_json|
|
161
|
+
instantiate_and_register_record(record_json)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Extract a collection from an API response
|
166
|
+
#
|
167
|
+
# @return [Hash]
|
168
|
+
#
|
169
|
+
# @api private
|
170
|
+
def extract_collection(json)
|
171
|
+
json[plural_path]
|
172
|
+
end
|
173
|
+
|
174
|
+
# Extract a record from an API response
|
175
|
+
#
|
176
|
+
# @return Hash
|
177
|
+
#
|
178
|
+
# @api private
|
179
|
+
def extract_record(json)
|
180
|
+
json && json[json_root]
|
181
|
+
end
|
182
|
+
|
183
|
+
# Build a new record
|
184
|
+
#
|
185
|
+
# @example
|
186
|
+
# new_order = client.Order.build(company_id: 123, order_number: 1234)
|
187
|
+
#
|
188
|
+
# @example
|
189
|
+
# new_order = client.Order.build
|
190
|
+
# new_order.order_number = 1234
|
191
|
+
#
|
192
|
+
# @param [#to_hash] initial attributes to set up the record
|
193
|
+
#
|
194
|
+
# @return [Gecko::Record::Base]
|
195
|
+
#
|
196
|
+
# @api public
|
197
|
+
def build(attributes={})
|
198
|
+
model_class.new(@client, attributes)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Save a record
|
202
|
+
#
|
203
|
+
# @params [Object] :record A Gecko::Record object
|
204
|
+
#
|
205
|
+
# @return [Boolean] whether the save was successful.
|
206
|
+
# If false the record will contain an errors hash
|
207
|
+
#
|
208
|
+
# @api private
|
209
|
+
def save(record)
|
210
|
+
if record.persisted?
|
211
|
+
update_record(record)
|
212
|
+
else
|
213
|
+
create_record(record)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
# Returns the json key for a record adapter
|
220
|
+
#
|
221
|
+
# @example
|
222
|
+
# product_adapter.json_root #=> "product"
|
223
|
+
#
|
224
|
+
# @return [String]
|
225
|
+
#
|
226
|
+
# @api private
|
227
|
+
def json_root
|
228
|
+
@model_name.to_s.underscore
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns the pluralized name of a record class used for generating API endpoint
|
232
|
+
#
|
233
|
+
# @return [String]
|
234
|
+
#
|
235
|
+
# @api private
|
236
|
+
def plural_path
|
237
|
+
json_root + 's'
|
238
|
+
end
|
239
|
+
|
240
|
+
# Returns the model class associated with an adapter
|
241
|
+
#
|
242
|
+
# @example
|
243
|
+
# product_adapter.model_class #=> Gecko::Record::Product
|
244
|
+
#
|
245
|
+
# @return [Class]
|
246
|
+
#
|
247
|
+
# @api private
|
248
|
+
def model_class
|
249
|
+
Gecko::Record.const_get(@model_name)
|
250
|
+
end
|
251
|
+
|
252
|
+
# Instantiates a record from it's JSON representation and registers
|
253
|
+
# it into the identity map
|
254
|
+
#
|
255
|
+
# @return [Gecko::Record::Base]
|
256
|
+
#
|
257
|
+
# @api private
|
258
|
+
def instantiate_and_register_record(record_json)
|
259
|
+
record = model_class.new(@client, record_json)
|
260
|
+
register_record(record)
|
261
|
+
record
|
262
|
+
end
|
263
|
+
|
264
|
+
# Registers a record into the identity map
|
265
|
+
#
|
266
|
+
# @return [Gecko::Record::Base]
|
267
|
+
#
|
268
|
+
# @api private
|
269
|
+
def register_record(record)
|
270
|
+
@identity_map[record.id] = record
|
271
|
+
end
|
272
|
+
|
273
|
+
# Create a record via API
|
274
|
+
#
|
275
|
+
# @return [OAuth2::Response]
|
276
|
+
#
|
277
|
+
# @api private
|
278
|
+
def create_record(record)
|
279
|
+
response = request(:post, plural_path, {
|
280
|
+
body: record.as_json,
|
281
|
+
raise_errors: false
|
282
|
+
})
|
283
|
+
handle_response(record, response)
|
284
|
+
end
|
285
|
+
|
286
|
+
# Update a record via API
|
287
|
+
#
|
288
|
+
# @return [OAuth2::Response]
|
289
|
+
#
|
290
|
+
# @api private
|
291
|
+
def update_record(record)
|
292
|
+
response = request(:put, plural_path + "/" + record.id.to_s, {
|
293
|
+
body: record.as_json,
|
294
|
+
raise_errors: false
|
295
|
+
})
|
296
|
+
handle_response(record, response)
|
297
|
+
end
|
298
|
+
|
299
|
+
# Handle the API response.
|
300
|
+
# - Updates the record if attributes are returned
|
301
|
+
# - Adds validation errors from a 422
|
302
|
+
#
|
303
|
+
# @return [OAuth2::Response]
|
304
|
+
#
|
305
|
+
# @api private
|
306
|
+
def handle_response(record, response)
|
307
|
+
case response.status
|
308
|
+
when 200..299
|
309
|
+
if response_json = extract_record(response.parsed)
|
310
|
+
record.attributes = response_json
|
311
|
+
register_record(record)
|
312
|
+
end
|
313
|
+
true
|
314
|
+
when 422
|
315
|
+
record.errors.from_response(response.parsed['errors'])
|
316
|
+
false
|
317
|
+
else
|
318
|
+
fail OAuth2::Error.new(response)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# Sets up the pagination metadata on a record adapter
|
323
|
+
#
|
324
|
+
# @api private
|
325
|
+
def set_pagination(headers)
|
326
|
+
@pagination = JSON.parse(headers["x-pagination"]) if headers["x-pagination"]
|
327
|
+
end
|
328
|
+
|
329
|
+
# Makes a request to the API.
|
330
|
+
#
|
331
|
+
# @param [Symbol] verb the HTTP request method
|
332
|
+
# @param [String] path the HTTP URL path of the request
|
333
|
+
# @param [Hash] opts the options to make the request with
|
334
|
+
# @option opts [Hash] :params params for request
|
335
|
+
#
|
336
|
+
# @return [OAuth2::Response]
|
337
|
+
#
|
338
|
+
# @api private
|
339
|
+
def request(verb, path, options={})
|
340
|
+
ActiveSupport::Notifications.instrument('request.gecko') do |payload|
|
341
|
+
payload[:verb] = verb
|
342
|
+
payload[:params] = options[:params]
|
343
|
+
payload[:body] = options[:body]
|
344
|
+
payload[:model_class] = model_class
|
345
|
+
payload[:request_path] = path
|
346
|
+
payload[:response] = @client.access_token.request(verb, path, options)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def record_not_found!(id)
|
351
|
+
fail RecordNotFound, "Couldn't find #{model_class.name} with id=#{id}"
|
352
|
+
end
|
353
|
+
|
354
|
+
def record_not_in_identity_map!(id)
|
355
|
+
fail RecordNotInIdentityMap, "Couldn't find #{model_class.name} with id=#{id}"
|
356
|
+
end
|
357
|
+
|
358
|
+
def verify_id_presence!(id)
|
359
|
+
if id.respond_to?(:empty?) ? id.empty? : !id
|
360
|
+
fail RecordNotFound, "Couldn't find #{model_class.name} without an ID"
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'gecko/record/base'
|
2
|
+
|
3
|
+
module Gecko
|
4
|
+
module Record
|
5
|
+
class Company < Base
|
6
|
+
belongs_to :assignee, class_name: 'User'
|
7
|
+
|
8
|
+
has_many :addresses
|
9
|
+
has_many :contacts
|
10
|
+
has_many :notes
|
11
|
+
|
12
|
+
attribute :name, String
|
13
|
+
attribute :description, String
|
14
|
+
attribute :company_code, String
|
15
|
+
attribute :phone_number, String
|
16
|
+
attribute :fax, String
|
17
|
+
attribute :email, String
|
18
|
+
attribute :website, String
|
19
|
+
attribute :company_type, String
|
20
|
+
|
21
|
+
attribute :status, String, readonly: true
|
22
|
+
|
23
|
+
attribute :tax_number, String
|
24
|
+
|
25
|
+
attribute :default_tax_rate, BigDecimal
|
26
|
+
attribute :default_tax_type_id, Integer
|
27
|
+
|
28
|
+
attribute :default_discount_rate, BigDecimal
|
29
|
+
|
30
|
+
# belongs_to :default_price_list, class_name: "PriceList"
|
31
|
+
# belongs_to :default_payment_term, class_name: "PaymentTerm"
|
32
|
+
end
|
33
|
+
|
34
|
+
class CompanyAdapter < BaseAdapter
|
35
|
+
# Override plural_path to properly pluralize company
|
36
|
+
def plural_path
|
37
|
+
'companies'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'gecko/record/base'
|
2
|
+
|
3
|
+
module Gecko
|
4
|
+
module Record
|
5
|
+
class Contact < Base
|
6
|
+
belongs_to :company
|
7
|
+
|
8
|
+
attribute :email, String
|
9
|
+
attribute :first_name, String
|
10
|
+
attribute :last_name, String
|
11
|
+
attribute :location, String
|
12
|
+
attribute :mobile, String
|
13
|
+
attribute :notes, String
|
14
|
+
attribute :phone_number, String
|
15
|
+
attribute :fax, String
|
16
|
+
attribute :position, String
|
17
|
+
attribute :phone, String
|
18
|
+
|
19
|
+
attribute :status, String, readonly: true
|
20
|
+
end
|
21
|
+
|
22
|
+
class ContactAdapter < BaseAdapter
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'gecko/record/base'
|
2
|
+
|
3
|
+
module Gecko
|
4
|
+
module Record
|
5
|
+
class Currency < Base
|
6
|
+
attribute :iso, String
|
7
|
+
attribute :name, String
|
8
|
+
attribute :rate, BigDecimal
|
9
|
+
attribute :symbol, String
|
10
|
+
attribute :separator, String
|
11
|
+
attribute :delimiter, String
|
12
|
+
attribute :precision, Integer
|
13
|
+
attribute :format, String
|
14
|
+
end
|
15
|
+
|
16
|
+
class CurrencyAdapter < BaseAdapter
|
17
|
+
# Override plural_path to properly pluralize currency
|
18
|
+
def plural_path
|
19
|
+
'currencies'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|