ooor 1.3.2 → 1.4.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.
@@ -0,0 +1,31 @@
1
+ # OOOR: Open Object On Rails
2
+ # Copyright (C) 2009-2010 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'base64'
19
+ module Base64
20
+ def serialize_binary_from_file(binary_path)
21
+ return Base64.encode64(File.read(binary_path))
22
+ end
23
+
24
+ def serialize_binary_from_content(content)
25
+ return Base64.encode64(content)
26
+ end
27
+
28
+ def unserialize_binary(content)
29
+ return Base64.decode64(content)
30
+ end
31
+ end
@@ -1,3 +1,20 @@
1
+ # OOOR: Open Object On Rails
2
+ # Copyright (C) 2009-2010 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
1
18
  #proxies all 'common' class of OpenERP server/bin/service/web_service.py properly
2
19
  module CommonService
3
20
  def global_login(user, password)
@@ -1,9 +1,27 @@
1
+ # OOOR: Open Object On Rails
2
+ # Copyright (C) 2009-2010 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
1
18
  #proxies all 'db' class of OpenERP server/bin/service/web_service.py properly
2
19
  module DbService
3
- def create(password=@config[:db_password], db_name='ooor_db', demo=true, lang='en-US', user_password=@config[:password] || 'admin')
20
+ def create(password=@config[:db_password], db_name='ooor_db', demo=true, lang='en_US', user_password=@config[:password] || 'admin')
4
21
  process_id = OpenObjectResource.try_with_pretty_error_log { OpenObjectResource.client(@base_url + "/db").call("create", password, db_name, demo, lang, user_password) }
5
22
  @config[:database] = db_name
6
- @config[:username] = user_password
23
+ @config[:username] = 'admin'
24
+ @config[:passowrd] = user_password
7
25
  while get_progress('admin', process_id) == [0, []]
8
26
  @logger.info "..."
9
27
  sleep(0.5)
@@ -1,11 +1,25 @@
1
+ # OOOR: Open Object On Rails
2
+ # Copyright (C) 2009-2010 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
1
18
  require 'xmlrpc/client'
2
19
  require 'rubygems'
3
20
  require 'active_resource'
4
21
  require 'app/ui/form_model'
5
22
  require 'app/models/uml'
6
- require 'set'
7
-
8
- #TODO implement passing session credentials to RPC methods (concurrent access of different user credentials in Rails)
9
23
 
10
24
  class OpenObjectResource < ActiveResource::Base
11
25
  include UML
@@ -25,27 +39,31 @@ class OpenObjectResource < ActiveResource::Base
25
39
  #similar to Object#const_get but for OpenERP model key
26
40
  def const_get(model_key)
27
41
  klass_name = class_name_from_model_key(model_key)
28
- klass = (self.scope_prefix ? Object.const_get(self.scope_prefix) : Object).const_defined?(klass_name) ? (self.scope_prefix ? Object.const_get(self.scope_prefix) : Object).const_get(klass_name) : @ooor.define_openerp_model(model_key, self.scope_prefix)
42
+ klass = (self.scope_prefix ? Object.const_get(self.scope_prefix) : Object).const_defined?(klass_name) ? (self.scope_prefix ? Object.const_get(self.scope_prefix) : Object).const_get(klass_name) : @ooor.define_openerp_model({'model' => model_key}, self.scope_prefix)
29
43
  klass.reload_fields_definition unless klass.fields_defined
30
44
  klass
31
45
  end
32
46
 
47
+ def create(attributes = {}, context={}, default_get_list=false, reload=true)
48
+ self.new(attributes, default_get_list, context).tap { |resource| resource.save(context, reload) }
49
+ end
50
+
33
51
  def reload_fields_definition(force = false)
34
- if not (self.to_s.match('IrModel') || self.to_s.match('IrModelFields')) and (force or not @fields_defined)#TODO have a way to force reloading @field_ids too eventually
35
- fields = (self.scope_prefix ? Object.const_get(self.scope_prefix) : Object).const_get('IrModelFields').find(@field_ids)
52
+ if force or not @fields_defined
53
+ @fields_defined = true
36
54
  @fields = {}
37
- fields.each do |field|
38
- case field.attributes['ttype']
55
+ rpc_execute("fields_get").each do |k, field|
56
+ case field['type']
39
57
  when 'many2one'
40
- @many2one_relations[field.attributes['name']] = field
58
+ @many2one_relations[k] = field
41
59
  when 'one2many'
42
- @one2many_relations[field.attributes['name']] = field
60
+ @one2many_relations[k] = field
43
61
  when 'many2many'
44
- @many2many_relations[field.attributes['name']] = field
62
+ @many2many_relations[k] = field
45
63
  when 'reference'
46
- @polymorphic_m2o_relations[field.attributes['name']] = field
64
+ @polymorphic_m2o_relations[k] = field
47
65
  else
48
- @fields[field.attributes['name']] = field
66
+ @fields[k] = field
49
67
  end
50
68
  end
51
69
  @relations_keys = @many2one_relations.keys + @one2many_relations.keys + @many2many_relations.keys + @polymorphic_m2o_relations.keys
@@ -60,7 +78,6 @@ class OpenObjectResource < ActiveResource::Base
60
78
  end
61
79
  logger.info "#{fields.size} fields loaded in model #{self.class}"
62
80
  end
63
- @fields_defined = true
64
81
  end
65
82
 
66
83
  # ******************** remote communication ********************
@@ -72,7 +89,7 @@ class OpenObjectResource < ActiveResource::Base
72
89
 
73
90
  def client(url)
74
91
  @clients ||= {}
75
- @clients[url] ||= XMLRPC::Client.new2(url, nil, 180)
92
+ @clients[url] ||= XMLRPC::Client.new2(url, nil, 900)
76
93
  end
77
94
 
78
95
  #corresponding method for OpenERP osv.execute(self, db, uid, obj, method, *args, **kw) method
@@ -163,7 +180,7 @@ class OpenObjectResource < ActiveResource::Base
163
180
  def cast_map_to_ruby!(map)
164
181
  map.each do |k, v|
165
182
  if self.fields[k] && v.is_a?(String) && !v.empty?
166
- case self.fields[k].ttype
183
+ case self.fields[k]['type']
167
184
  when 'datetime'
168
185
  map[k] = Time.parse(v)
169
186
  when 'date'
@@ -231,7 +248,7 @@ class OpenObjectResource < ActiveResource::Base
231
248
  record.each_pair do |k,v|
232
249
  r[k.to_sym] = v
233
250
  end
234
- active_resources << instantiate_record(r, prefix_options)
251
+ active_resources << instantiate_record(r, prefix_options, context)
235
252
  end
236
253
  unless is_collection
237
254
  return active_resources[0]
@@ -240,8 +257,8 @@ class OpenObjectResource < ActiveResource::Base
240
257
  end
241
258
 
242
259
  #overriden because loading default fields is all the rage but we don't want them when reading a record
243
- def instantiate_record(record, prefix_options = {})
244
- new(record, [], {}).tap do |resource|
260
+ def instantiate_record(record, prefix_options = {}, context = {})
261
+ new(record, [], context).tap do |resource|
245
262
  resource.prefix_options = prefix_options
246
263
  end
247
264
  end
@@ -251,7 +268,21 @@ class OpenObjectResource < ActiveResource::Base
251
268
 
252
269
  # ******************** instance methods ********************
253
270
 
254
- attr_accessor :relations, :loaded_relations, :ir_model_data_id
271
+ attr_accessor :relations, :loaded_relations, :ir_model_data_id, :object_session
272
+
273
+ def object_db; object_session[:database] || self.class.database || self.class.ooor.config[:database]; end
274
+ def object_uid;object_session[:user_id] || self.class.user_id || self.class.ooor.config[:user_id]; end
275
+ def object_pass; object_session[:password] || self.class.password || self.class.ooor.config[:password]; end
276
+
277
+ #try to wrap the object context inside the query.
278
+ def rpc_execute(method, *args)
279
+ if args[-1].is_a? Hash
280
+ args[-1] = self.class.ooor.global_context.merge(object_session[:context]).merge(args[-1])
281
+ elsif args.is_a?(Array)
282
+ args += [self.class.ooor.global_context.merge(object_session[:context])]
283
+ end
284
+ self.class.rpc_execute_with_all(object_db, object_uid, object_pass, self.class.openerp_model, method, *args)
285
+ end
255
286
 
256
287
  def cast_relations_to_openerp!
257
288
  @relations.reject! do |k, v| #reject non asigned many2one or empty list
@@ -282,7 +313,7 @@ class OpenObjectResource < ActiveResource::Base
282
313
  @relations[k] = new_rel
283
314
  else
284
315
  self.class.many2one_relations.each do |k2, field| #try to cast the relation to an inherited o2m or m2m:
285
- linked_class = self.class.const_get(field.relation)
316
+ linked_class = self.class.const_get(field['relation'])
286
317
  new_rel = self.cast_relation(k, v, linked_class.one2many_relations, linked_class.many2many_relations)
287
318
  @relations[k] = new_rel and break if new_rel
288
319
  end
@@ -323,13 +354,12 @@ class OpenObjectResource < ActiveResource::Base
323
354
  end
324
355
 
325
356
  def display_available_fields
326
- msg = "\n*** DIRECTLY AVAILABLE FIELDS ON OBJECT #{self} ARE: ***"
327
- msg << "\n\n" << self.class.fields.sort {|a,b| a[1].ttype<=>b[1].ttype}.map {|i| "#{i[1].ttype} --- #{i[0]}"}.join("\n")
328
- msg << "\n\n" << self.class.many2one_relations.map {|k, v| "many2one --- #{v.relation} --- #{k}"}.join("\n")
329
- msg << "\n\n" << self.class.one2many_relations.map {|k, v| "one2many --- #{v.relation} --- #{k}"}.join("\n")
330
- msg << "\n\n" << self.class.many2many_relations.map {|k, v| "many2many --- #{v.relation} --- #{k}"}.join("\n")
331
- msg << "\n\n" << self.class.polymorphic_m2o_relations.map {|k, v| "polymorphic_m2o --- #{v.relation} --- #{k}"}.join("\n")
332
- msg << "\n\nYOU CAN ALSO USE THE INHERITED FIELDS FROM THE INHERITANCE MANY2ONE RELATIONS OR THE OBJECT METHODS...\n\n"
357
+ msg = "\n*** AVAILABLE FIELDS ON OBJECT #{self} ARE: ***"
358
+ msg << "\n\n" << self.class.fields.sort {|a,b| a[1]['type']<=>b[1]['type']}.map {|i| "#{i[1]['type']} --- #{i[0]}"}.join("\n")
359
+ msg << "\n\n" << self.class.many2one_relations.map {|k, v| "many2one --- #{v['relation']} --- #{k}"}.join("\n")
360
+ msg << "\n\n" << self.class.one2many_relations.map {|k, v| "one2many --- #{v['relation']} --- #{k}"}.join("\n")
361
+ msg << "\n\n" << self.class.many2many_relations.map {|k, v| "many2many --- #{v['relation']} --- #{k}"}.join("\n")
362
+ msg << "\n\n" << self.class.polymorphic_m2o_relations.map {|k, v| "polymorphic_m2o --- #{v['relation']} --- #{k}"}.join("\n")
333
363
  self.class.logger.debug msg
334
364
  end
335
365
 
@@ -339,49 +369,55 @@ class OpenObjectResource < ActiveResource::Base
339
369
  end
340
370
 
341
371
  #takes care of reading OpenERP default field values.
342
- #FIXME: until OpenObject explicits inheritances, we load all default values of all related fields, unless specified in default_get_list
343
372
  def initialize(attributes = {}, default_get_list=false, context={})
344
- @attributes = {}
373
+ @attributes = {}
345
374
  @prefix_options = {}
346
375
  @ir_model_data_id = attributes.delete(:ir_model_data_id)
347
- if ['ir.model', 'ir.model.fields'].index(self.class.openerp_model) || default_get_list == []
376
+ @object_session = {}
377
+ @object_session[:user_id] = context.delete :user_id
378
+ @object_session[:database] = context.delete :database
379
+ @object_session[:password] = context.delete :password
380
+ @object_session[:context] = context
381
+ if default_get_list == []
348
382
  load(attributes)
349
383
  else
350
- self.class.reload_fields_definition() unless self.class.fields_defined
351
- default_get_list ||= Set.new(self.class.many2one_relations.reject {|k, v| attributes.keys.index(k.to_sym)}.collect {|k, field| self.class.const_get(field.relation).fields.keys}.flatten + self.class.fields.keys).to_a
352
- load(self.class.rpc_execute("default_get", default_get_list, context).symbolize_keys!.merge(attributes.symbolize_keys!))
384
+ load(rpc_execute("default_get", rpc_execute("fields_get").keys, @object_session[:context]).symbolize_keys!.merge(attributes.symbolize_keys!))
353
385
  end
354
386
  end
355
387
 
388
+ def save(context={}, reload=true)
389
+ new? ? create(context, reload) : update(context, reload)
390
+ end
391
+
356
392
  #compatible with the Rails way but also supports OpenERP context
357
393
  def create(context={}, reload=true)
358
- self.id = self.class.rpc_execute('create', to_openerp_hash!, context)
394
+ self.id = rpc_execute('create', to_openerp_hash!, context)
359
395
  IrModelData.create(:model => self.class.openerp_model, :module => @ir_model_data_id[0], :name=> @ir_model_data_id[1], :res_id => self.id) if @ir_model_data_id
360
396
  reload_from_record!(self.class.find(self.id, :context => context)) if reload
361
397
  end
362
398
 
363
399
  #compatible with the Rails way but also supports OpenERP context
364
400
  def update(context={}, reload=true)
365
- self.class.rpc_execute('write', self.id, to_openerp_hash!, context)
401
+ rpc_execute('write', self.id, to_openerp_hash!, context)
366
402
  reload_from_record!(self.class.find(self.id, :context => context)) if reload
367
403
  end
368
404
 
369
405
  #compatible with the Rails way but also supports OpenERP context
370
406
  def destroy(context={})
371
- self.class.rpc_execute('unlink', [self.id], context)
407
+ rpc_execute('unlink', [self.id], context)
372
408
  end
373
409
 
374
410
  #OpenERP copy method, load persisted copied Object
375
411
  def copy(defaults={}, context={})
376
- self.class.find(self.class.rpc_execute('copy', self.id, defaults, context), :context => context)
412
+ self.class.find(rpc_execute('copy', self.id, defaults, context), :context => context)
377
413
  end
378
414
 
379
415
  #Generic OpenERP rpc method call
380
- def call(method, *args) self.class.rpc_execute(method, *args) end
416
+ def call(method, *args) rpc_execute(method, *args) end
381
417
 
382
418
  #Generic OpenERP on_change method
383
419
  def on_change(on_change_method, field_name, field_value, *args)
384
- result = self.class.rpc_execute(on_change_method, self.id && [id] || [], *args)
420
+ result = self.class.rpc_execute_with_all(object_db, object_uid, object_pass, self.class.openerp_model, on_change_method, self.id && [id] || [], *args) #OpenERP doesn't accept context systematically in on_change events unfortunately
385
421
  if result["warning"]
386
422
  self.class.logger.info result["warning"]["title"]
387
423
  self.class.logger.info result["warning"]["message"]
@@ -390,9 +426,9 @@ class OpenObjectResource < ActiveResource::Base
390
426
  end
391
427
 
392
428
  #wrapper for OpenERP exec_workflow Business Process Management engine
393
- def wkf_action(action, context={})
394
- self.class.rpc_exec_workflow(action, self.id) #FIXME looks like OpenERP exec_workflow doesn't accept context but it might be a bug
395
- reload_from_record!(self.class.find(self.id, :context => context))
429
+ def wkf_action(action, context={}, reload=true)
430
+ self.class.rpc_exec_workflow_with_all(object_db, object_uid, object_pass, self.class.openerp_model, action, self.id) #FIXME looks like OpenERP exec_workflow doesn't accept context but it might be a bug
431
+ reload_from_record!(self.class.find(self.id, :context => context)) if reload
396
432
  end
397
433
 
398
434
  def old_wizard_step(wizard_name, step='init', wizard_id=nil, form={}, context={})
@@ -408,11 +444,11 @@ class OpenObjectResource < ActiveResource::Base
408
444
  def relationnal_result(method_name, *arguments)
409
445
  self.class.reload_fields_definition unless self.class.fields_defined
410
446
  if self.class.many2one_relations.has_key?(method_name)
411
- load_relation(self.class.many2one_relations[method_name].relation, @relations[method_name][0], *arguments)
447
+ load_relation(self.class.many2one_relations[method_name]['relation'], @relations[method_name][0], *arguments)
412
448
  elsif self.class.one2many_relations.has_key?(method_name)
413
- load_relation(self.class.one2many_relations[method_name].relation, @relations[method_name], *arguments)
449
+ load_relation(self.class.one2many_relations[method_name]['relation'], @relations[method_name], *arguments)
414
450
  elsif self.class.many2many_relations.has_key?(method_name)
415
- load_relation(self.class.many2many_relations[method_name].relation, @relations[method_name], *arguments)
451
+ load_relation(self.class.many2many_relations[method_name]['relation'], @relations[method_name], *arguments)
416
452
  elsif self.class.polymorphic_m2o_relations.has_key?(method_name)
417
453
  values = @relations[method_name].split(',')
418
454
  load_relation(values[0], values[1].to_i, *arguments)
@@ -426,18 +462,18 @@ class OpenObjectResource < ActiveResource::Base
426
462
  is_assign = method_name.end_with?('=')
427
463
  method_key = method_name.sub('=', '')
428
464
  return super if attributes.has_key?(method_key)
429
- return self.class.rpc_execute(method_name, *arguments) unless arguments.empty? || is_assign
465
+ return rpc_execute(method_name, *arguments) unless arguments.empty? || is_assign
430
466
 
431
467
  self.class.reload_fields_definition() unless self.class.fields_defined
432
468
 
433
469
  if is_assign
434
- known_relations = self.class.relations_keys + self.class.many2one_relations.collect {|k, field| self.class.const_get(field.relation).relations_keys}.flatten
470
+ known_relations = self.class.relations_keys + self.class.many2one_relations.collect {|k, field| self.class.const_get(field['relation']).relations_keys}.flatten
435
471
  if known_relations.index(method_key)
436
472
  @relations[method_key] = arguments[0]
437
473
  @loaded_relations[method_key] = arguments[0]
438
474
  return
439
475
  end
440
- know_fields = self.class.fields.keys + self.class.many2one_relations.collect {|k, field| self.class.const_get(field.relation).fields.keys}.flatten
476
+ know_fields = self.class.fields.keys + self.class.many2one_relations.collect {|k, field| self.class.const_get(field['relation']).fields.keys}.flatten
441
477
  @attributes[method_key] = arguments[0] and return if know_fields.index(method_key)
442
478
  end
443
479
 
@@ -450,27 +486,9 @@ class OpenObjectResource < ActiveResource::Base
450
486
  result = relationnal_result(method_name, *arguments)
451
487
  @loaded_relations[method_name] = result and return result if result
452
488
 
453
- #maybe the relation is inherited or could be inferred from a related field
454
- self.class.many2one_relations.each do |k, field| #TODO could be recursive eventually
455
- if @relations[k] #we only care if instance has a relation
456
- related_model = self.class.const_get(field.relation)
457
- related_model.reload_fields_definition() unless related_model.fields_defined
458
- if related_model.relations_keys.index(method_key)
459
- @loaded_relations[k] ||= load_relation(field.relation, @relations[k][0], *arguments)
460
- model = @loaded_relations[k]
461
- model.loaded_relations[method_key] ||= model.relationnal_result(method_key, *arguments)
462
- return model.loaded_relations[method_key] if model.loaded_relations[method_key]
463
- end
464
- elsif is_assign
465
- klazz = self.class.const_get(field.relation)
466
- @relations[method_key] = arguments[0] and return if klazz.relations_keys.index(method_key)
467
- @attributes[method_key] = arguments[0] and return if klazz.fields.keys.index(method_key)
468
- end
469
- end
470
-
471
489
  if id
472
490
  arguments += [{}] unless arguments.last.is_a?(Hash)
473
- self.class.rpc_execute(method_key, [id], *arguments) #we assume that's an action
491
+ rpc_execute(method_key, [id], *arguments) #we assume that's an action
474
492
  else
475
493
  super
476
494
  end
@@ -1,3 +1,20 @@
1
+ # OOOR: Open Object On Rails
2
+ # Copyright (C) 2009-2010 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
1
18
  module UML
2
19
  #usage: UML.print_uml or with options: UML.print_uml(:all, : detailed) or MyOpenObjectResource.print_uml or UML.print_uml([list_of_classes], :all, :detailed)
3
20
 
@@ -17,7 +34,7 @@ module UML
17
34
  def self.display_fields(clazz)
18
35
  s = ""
19
36
  clazz.reload_fields_definition if clazz.fields.empty?
20
- clazz.fields.sort {|a,b| a[1].ttype <=> b[1].ttype}.each {|i| s << "+ #{i[1].ttype} : #{i[0]}\\l\\n"}
37
+ clazz.fields.sort {|a,b| a[1]['type'] <=> b[1]['type']}.each {|i| s << "+ #{i[1]['type']} : #{i[0]}\\l\\n"}
21
38
  s
22
39
  end
23
40
 
@@ -170,8 +187,8 @@ module UML
170
187
  private
171
188
 
172
189
  def self.get_target(is_reverse, local, enabled_targets, field, model)
173
- if (is_reverse && !local) || (!enabled_targets) || enabled_targets.index(field.relation)
174
- model.const_get(field.relation)
190
+ if (is_reverse && !local) || (!enabled_targets) || enabled_targets.index(field['relation'])
191
+ model.const_get(field['relation'])
175
192
  else
176
193
  false
177
194
  end
@@ -1,3 +1,20 @@
1
+ # OOOR: Open Object On Rails
2
+ # Copyright (C) 2009-2010 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
1
18
  module ActionWindowModule
2
19
  def open(mode='tree', ids=nil)
3
20
  if view_mode.index(mode)