ooor 1.6.5 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009-2012 Raphaël Valyi - Akretion LTDA
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- OOOR - OpenObject On Rails
1
+ OOOR - OpenObject On Ruby:
2
2
  ====
3
3
 
4
4
  <table>
@@ -106,14 +106,18 @@ This will bring you in a standard IRB interpreter with an OOOR client already co
106
106
 
107
107
  Let's test OOOR in an irb console (irb command):
108
108
 
109
- $ require 'rubygems'
110
- $ require 'ooor'
111
- $ Ooor.new(:url => 'http://localhost:8069/xmlrpc', :database => 'mybase', :username => 'admin', :password => 'admin')
109
+ ```ruby
110
+ require 'rubygems'
111
+ require 'ooor'
112
+ Ooor.new(:url => 'http://localhost:8069/xmlrpc', :database => 'mybase', :username => 'admin', :password => 'admin')
113
+ ```
112
114
 
113
115
  This should load all your OpenERP models into Ruby proxy Activeresource objects. Of course there are option to load only some models.
114
116
  Let's try to retrieve the user with id 1:
115
117
 
116
- $ ResUsers.find(1)
118
+ ```ruby
119
+ ResUsers.find(1)
120
+ ```
117
121
 
118
122
  (in case you have an error like "no such file to load -- net/https", then on Debian/Ubuntu, you might need to do before: apt-get install libopenssl-ruby)
119
123
 
@@ -131,52 +135,62 @@ Note: Ruby proxies objects are named after OpenERP models in but removing the '.
131
135
 
132
136
  Basic finders:
133
137
 
134
- $ ProductProduct.find(1)
135
- $ ProductProduct.find([1,2])
136
- $ ProductProduct.find([1])
137
- $ ProductProduct.find(:all)
138
- $ ProductProduct.find(:last)
139
-
138
+ ```ruby
139
+ ProductProduct.find(1)
140
+ ProductProduct.find([1,2])
141
+ ProductProduct.find([1])
142
+ ProductProduct.find(:all)
143
+ ProductProduct.find(:last)
144
+ ```
140
145
 
141
146
  OpenERP domain support (same as OpenERP):
142
147
 
143
- $ ResPartner.find(:all, :domain=>[['supplier', '=', 1],['active','=',1]])
144
- More subtle now, remember OpenERP use a kind of inverse polish notation for complex domains,
145
- here we look for a product in category 1 AND which name is either 'PC1' OR 'PC2':
146
- $ ProductProduct.find(:all, :domain=>[['categ_id','=',1],'|',['name', '=', 'PC1'],['name','=','PC2']])
148
+ ```ruby
149
+ ResPartner.find(:all, :domain=>[['supplier', '=', 1],['active','=',1]])
150
+ #More subtle now, remember OpenERP use a kind of inverse polish notation for complex domains,
151
+ #here we look for a product in category 1 AND which name is either 'PC1' OR 'PC2':
152
+ ProductProduct.find(:all, :domain=>[['categ_id','=',1],'|',['name', '=', 'PC1'],['name','=','PC2']])
153
+ ```
147
154
 
148
155
 
149
156
  OpenERP context support (same as OpenERP):
150
157
 
151
- $ ProductProduct.find(1, :context => {:my_key => 'value'})
152
-
158
+ ```ruby
159
+ ProductProduct.find(1, :context => {:my_key => 'value'})
160
+ ```
153
161
 
154
162
  Request params or ActiveResource equivalence of OpenERP domain (but degraded as only the = operator is supported, else use domain):
155
163
 
156
- $ ResPartner.find(:all, :params => {:supplier => true})
157
-
164
+ ```ruby
165
+ ResPartner.find(:all, :params => {:supplier => true})
166
+ ```
158
167
 
159
168
  OpenERP search method:
160
169
 
161
- $ ResPartner.search([['name', 'ilike', 'a']], 0, 2)
170
+ ```ruby
171
+ ResPartner.search([['name', 'ilike', 'a']], 0, 2)
172
+ ```
162
173
 
163
174
  Arguments are: domain, offset=0, limit=false, order=false, context={}, count=false
164
175
 
165
176
 
166
177
  Relations (many2one, one2many, many2many) support:
167
178
 
168
- $ SaleOrder.find(1).order_line #one2many relation
169
- $ p = ProductProduct.find(1)
170
- $ p.product_tmpl_id #many2one relation
171
- $ p.taxes_id #automagically reads man2many relation inherited via the product_tmpl_id inheritance relation
172
- $ p.taxes_id = [1,2] #save a many2many relation, notice how we bypass the awkward OpenERP syntax for many2many (would require [6,0, [1,2]]) ,
173
- $ p.save #assigns taxes with id 1 and 2 as sale taxes,
174
- see [the official OpenERP documentation](http://doc.openerp.com/developer/5_18_upgrading_server/19_1_upgrading_server.html?highlight=many2many)
179
+ ```ruby
180
+ SaleOrder.find(1).order_line #one2many relation
181
+ p = ProductProduct.find(1)
182
+ p.product_tmpl_id #many2one relation
183
+ p.taxes_id #automagically reads man2many relation inherited via the product_tmpl_id inheritance relation
184
+ p.taxes_id = [1,2] #save a many2many relation, notice how we bypass the awkward OpenERP syntax for many2many (would require [6,0, [1,2]]) ,
185
+ p.save #assigns taxes with id 1 and 2 as sale taxes,
186
+ see [the official OpenERP documentation](http://doc.openerp.com/developer/5_18_upgrading_server/19_1_upgrading_server.html?highlight=many2many)```
175
187
 
176
188
 
177
189
  Inherited relations support:
178
190
 
179
- $ ProductProduct.find(1).categ_id #where categ_id is inherited from the ProductTemplate
191
+ ```ruby
192
+ ProductProduct.find(1).categ_id #where categ_id is inherited from the ProductTemplate
193
+ ```
180
194
 
181
195
  Please notice that loaded relations are cached (to avoid hitting OpenERP over and over)
182
196
  until the root object is reloaded (after save/update for instance).
@@ -184,48 +198,57 @@ until the root object is reloaded (after save/update for instance).
184
198
 
185
199
  Load only specific fields support (faster than loading all fields):
186
200
 
187
- $ ProductProduct.find(1, :fields=>["state", "id"])
188
- $ ProductProduct.find(:all, :fields=>["state", "id"])
189
- $ ProductProduct.find([1,2], :fields=>["state", "id"])
190
- $ ProductProduct.find(:all, :fields=>["state", "id"])
201
+ ```ruby
202
+ ProductProduct.find(1, :fields=>["state", "id"])
203
+ ProductProduct.find(:all, :fields=>["state", "id"])
204
+ ProductProduct.find([1,2], :fields=>["state", "id"])
205
+ ProductProduct.find(:all, :fields=>["state", "id"])
206
+ ```
191
207
 
192
208
  even in relations:
193
209
 
194
- $ SaleOrder.find(1).order_line(:fields => ["state"])
195
-
210
+ ```ruby
211
+ SaleOrder.find(1).order_line(:fields => ["state"])
212
+ ```
196
213
 
197
214
  Create:
198
215
 
199
- $ pc = ProductCategory.new(:name => 'Categ From Rails!')
200
- $ #<ProductCategory:0xb702c42c @prefix_options={}, @attributes={"name"=>"Categ From Rails!"}>
201
- $ pc.create
202
- $ pc.id
203
- $ => 14
216
+ ```ruby
217
+ pc = ProductCategory.new(:name => 'Categ From Rails!')
218
+ #<ProductCategory:0xb702c42c @prefix_options={}, @attributes={"name"=>"Categ From Rails!"}>
219
+ pc.create
220
+ pc.id
221
+ #$ => 14
222
+ ```
204
223
 
205
224
 
206
225
  Update:
207
226
 
208
- $ pc.name = "A new name"
209
- $ pc.save
210
-
227
+ ```ruby
228
+ pc.name = "A new name"
229
+ pc.save
230
+ ```
211
231
 
212
232
  Copy:
213
233
 
214
- $ copied_object = pc.copy({:categ_id => 2}) #first optionnal arg is new default values, second is context
215
-
234
+ ```ruby
235
+ copied_object = pc.copy({:categ_id => 2}) #first optionnal arg is new default values, second is context
236
+ ```
216
237
 
217
238
  Delete:
218
239
 
219
- $ pc.destroy
220
-
240
+ ```ruby
241
+ pc.destroy
242
+ ```
221
243
 
222
244
  Call workflow:
223
245
 
224
- $ s = SaleOrder.find(2)
225
- $ s.wkf_action('cancel')
226
- $ s.state
227
- $ => 'cancel'
228
-
246
+ ```ruby
247
+ s = SaleOrder.find(2)
248
+ s.wkf_action('cancel')
249
+ s.state
250
+ #=> 'cancel'
251
+ ```
229
252
 
230
253
  On Change methods:
231
254
 
@@ -236,9 +259,11 @@ you need to explicitely tell the on_change name, the parameter name that changed
236
259
  enfore the on_change syntax (looking at the OpenERP model code or view or XML/RPC logs will help you to find out). But
237
260
  ultimately it works:
238
261
 
239
- $ l = SaleOrderLine.new
240
- $ l.on_change('product_id_change', :product_id, 20, 1, 20, 1, false, 1, false, false, 7, 'en_US', true, false, false, false)
241
- $ => #<SaleOrderLine:0x7f76118b4348 @prefix_options={}, @relations={"product_uos"=>false, "product_id"=>20, "product_uom"=>1, "tax_id"=>[]}, @loaded_relations={}, @attributes={"name"=>"[TOW1] ATX Mid-size Tower", "product_uos_qty"=>1, "delay"=>1.0, "price_unit"=>37.5, "type"=>"make_to_stock", "th_weight"=>0}>
262
+ ```ruby
263
+ l = SaleOrderLine.new
264
+ l.on_change('product_id_change', :product_id, 20, 1, 20, 1, false, 1, false, false, 7, 'en_US', true, false, false, false)
265
+ #=> #<SaleOrderLine:0x7f76118b4348 @prefix_options={}, @relations={"product_uos"=>false, "product_id"=>20, "product_uom"=>1, "tax_id"=>[]}, @loaded_relations={}, @attributes={"name"=>"[TOW1] ATX Mid-size Tower", "product_uos_qty"=>1, "delay"=>1.0, "price_unit"=>37.5, "type"=>"make_to_stock", "th_weight"=>0}>
266
+ ```
242
267
  Notice that it reloads the Objects attrs and print warning message accordingly
243
268
 
244
269
 
@@ -247,12 +272,14 @@ On the fly one2many object graph update/creation:
247
272
  Just like the OpenERP GTK client (and unlike the web client), in OOOR you can pass create/update
248
273
  one2many relation in place directly. For instance:
249
274
 
250
- $ so = SaleOrder.new
251
- $ so.on_change('onchange_partner_id', :partner_id, 1, 1, false) #auto-complete the address and other data based on the partner
252
- $ so.order_line = [SaleOrderLine.new(:name => 'sl1', :product_id => 1, :price_unit => 42, :product_uom => 1)] #create one order line
253
- $ so.save
254
- $ so.amount_total
255
- $ => 42.0
275
+ ```ruby
276
+ so = SaleOrder.new
277
+ so.on_change('onchange_partner_id', :partner_id, 1, 1, false) #auto-complete the address and other data based on the partner
278
+ so.order_line = [SaleOrderLine.new(:name => 'sl1', :product_id => 1, :price_unit => 42, :product_uom => 1)] #create one order line
279
+ so.save
280
+ so.amount_total
281
+ #=> 42.0
282
+ ```
256
283
 
257
284
 
258
285
  Call aribtrary method:
@@ -261,22 +288,27 @@ Call aribtrary method:
261
288
  $ or object.call(method_name, args*) #were args is an aribtrary list of arguments
262
289
 
263
290
  Class methods from are osv.py/orm.py proxied to OpenERP directly (as the web client does):
264
- $ ResPartner.name_search('ax', [], 'ilike', {})
265
- $ ProductProduct.fields_view_get(132, 'tree', {})
291
+
292
+ ```ruby
293
+ ResPartner.name_search('ax', [], 'ilike', {})
294
+ ProductProduct.fields_view_get(132, 'tree', {})
295
+ ```
266
296
 
267
297
 
268
- Call old style wizards:
298
+ Call old style wizards (OpenERP v5):
269
299
 
270
- $ inv = AccountInvoice.find(4)
271
- $ #in case the inv.state is 'draft', do inv.wkf_action('invoice_open')
272
- $ wizard = inv.old_wizard_step('account.invoice.pay') #tip: you can inspect the wizard fields, arch and datas
273
- $ wizard.reconcile({:journal_id => 6, :name =>"from_rails"}) #if you want to pay all; will give you a reloaded invoice
274
- $ inv.state
275
- $ => "paid"
276
- $ #or if you want a payment with a write off:
277
- $ wizard.writeoff_check({"amount" => 12, "journal_id" => 6, "name" =>'from_rails'}) #use the button name as the wizard method
278
- $ wizard.reconcile({required missing write off fields...}) #will give you a reloaded invoice because state is 'end'
279
- $ TODO test and document new osv_memory wizards API
300
+ ```ruby
301
+ inv = AccountInvoice.find(4)
302
+ #in case the inv.state is 'draft', do inv.wkf_action('invoice_open')
303
+ wizard = inv.old_wizard_step('account.invoice.pay') #tip: you can inspect the wizard fields, arch and datas
304
+ wizard.reconcile({:journal_id => 6, :name =>"from_rails"}) #if you want to pay all; will give you a reloaded invoice
305
+ inv.state
306
+ #=> "paid"
307
+ #or if you want a payment with a write off:
308
+ wizard.writeoff_check({"amount" => 12, "journal_id" => 6, "name" =>'from_rails'}) #use the button name as the wizard method
309
+ wizard.reconcile({required missing write off fields...}) #will give you a reloaded invoice because state is 'end'
310
+ #TODO test and document new osv_memory wizards API
311
+ ```
280
312
 
281
313
 
282
314
  Absolute OpenERP ids aka ir_model_data:
@@ -286,39 +318,48 @@ We are here speaking about the string id of the XML or CSV records, eventually p
286
318
  Using those ids rather than the SQL ids is a good idea to avoid relying on a particular installation.
287
319
  In OOOR, you can both retrieve one or several records using those ids, like for instance:
288
320
 
289
- $ ProductCategory.find('product.product_category_3')
321
+ ```ruby
322
+ ProductCategory.find('product.product_category_3')
323
+ ```
290
324
 
291
325
  Notice that the 'product.' module prefix is optional here but important if you have similar ids in different module scopes.
292
326
  You can also create a resource and it's ir_model_data record alltogether using the ir_mode_data_id param:
293
327
 
294
- $ ProductCategory.create(:name => 'rails_categ', :ir_model_data_id =>['product', 'categ_x']) #1st tab element is the module, 2nd the id in the module
295
-
328
+ ```ruby
329
+ ProductCategory.create(:name => 'rails_categ', :ir_model_data_id =>['product', 'categ_x']) #1st tab element is the module, 2nd the id in the module
330
+ ```
296
331
 
297
332
  Obtain report binary data:
298
333
 
299
334
  To obtain the binary data of an object report simply use the function get_report_data(report_name). This function returns a list that contains the binary data encoded in base64 and a string with the file format.
300
335
  Example:
301
-
302
- $ inv = AccountInvoice.find(3)
303
- $ report = inv.get_report_data('account.invoice') #account.invoice is the service name defined in Invoices report
304
- $ #Save the report to a file
305
- $ #report[1] contains the file extension and report[0] contains the binary data of the report encoded in base64
306
- $ File.open("invoice_report.#{report[1]}", "w") {|f| f.write(Base64.decode64(report[0]))}
336
+
337
+ ```ruby
338
+ inv = AccountInvoice.find(3)
339
+ report = inv.get_report_data('account.invoice') #account.invoice is the service name defined in Invoices report
340
+ #Save the report to a file
341
+ #report[1] contains the file extension and report[0] contains the binary data of the report encoded in base64
342
+ File.open("invoice_report.#{report[1]}", "w") {|f| f.write(Base64.decode64(report[0]))}
343
+ ```
307
344
 
308
345
  Change logged user:
309
346
 
310
347
  An Ooor client can have a global user logged in, to change it:
311
348
 
312
- $ Ooor.global_login('demo', 'demo')
313
- $ s = SaleOrder.find(2)
314
- $ => 'Access denied error'
349
+ ```ruby
350
+ Ooor.global_login('demo', 'demo')
351
+ s = SaleOrder.find(2)
352
+ #=> 'Access denied error'
353
+ ```
315
354
 
316
355
  Instead, every Ooor business objects can also belong to some specific user. To achieve that, generate your object passing
317
356
  proper :user_id and :password parameters inside the context of the method creating the object (typically a find).
318
357
  Notice that methods invoked on an objet use the same credentials as the business objects.
319
358
  Objects generated by this object (by a call to an association for instance) will also have the same credentials.
320
359
 
321
- $ p = ProductProduct.find(1, :context => {:user_id=>3, :password=>'test'})
360
+ ```ruby
361
+ p = ProductProduct.find(1, :context => {:user_id=>3, :password=>'test'})
362
+ ```
322
363
 
323
364
  This is tipycally the system you will use in a Ruby (Rails or not) web application.
324
365
 
@@ -327,8 +368,10 @@ Change log level:
327
368
  By default the log level is very verbose (debug level) to help newcomers to jumpstart.
328
369
  However you might want to change that. 2 solutions:
329
370
 
330
- $ Ooor.logger.level = 1 #available levels are those of the standard Ruby Logger class: 0 debug, 1 info, 2 error
331
- $ In the config yaml file or hash, set the :log_level parameter
371
+ ```ruby
372
+ Ooor.logger.level = 1 #available levels are those of the standard Ruby Logger class: 0 debug, 1 info, 2 error
373
+ ```
374
+ In the config yaml file or hash, set the :log_level parameter
332
375
 
333
376
 
334
377
  [Drawing OpenERP UML diagrams with OOOR](http://wiki.github.com/rvalyi/ooor/drawing-openerp-uml-diagrams-with-ooor)
data/bin/ooor CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- puts "*** OOOR - OpenObject on Ruby! Published under the AGPL license by Akretion.com ***"
3
+ puts "*** OOOR - OpenObject on Ruby! Published under the MIT license by Akretion.com ***"
4
4
 
5
5
  require 'irb'
6
6
  require 'rubygems'
@@ -9,7 +9,7 @@ require 'irb/completion'
9
9
 
10
10
  unless ARGV.empty?
11
11
  username = ARGV[0].split(".")[0]
12
- database = ARGV[0].split(".")[1].split("@")[0]
12
+ database = ARGV[0].split(".")[1..100].join(".").split("@")[0]
13
13
  if ARGV[0].index("@")
14
14
  base_url = ARGV[0].split("@")[1]
15
15
  else
@@ -29,7 +29,9 @@ unless ARGV.empty?
29
29
  password = ARGV[1]
30
30
  else
31
31
  puts "password?"
32
+ system "stty -echo"
32
33
  password = $stdin.gets.chomp!
34
+ system "stty echo"
33
35
  end
34
36
 
35
37
  if ARGV[1] == "-s" || ARGV[2] == "-s" #secure mode
@@ -0,0 +1,137 @@
1
+ # OOOR: OpenObject On Ruby
2
+ # Copyright (C) 2009-2012 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Akretion: Raphaël Valyi: CampToCamp: Nicolas Bessi, Joel Grand-Guillaume
4
+ # Licensed under the MIT license, see MIT-LICENSE file
5
+
6
+ Ooor.xtend('ir.module.module') do
7
+
8
+ ##########################################################################
9
+ # Get recursively the whole list of modules dependencies
10
+ # for a list of modules.
11
+ # Do not add the module if it already exists in the input list
12
+ # Input :
13
+ # - modules : A [] of valid IrModuleModule instances with dependencies_id attribute
14
+ # Return
15
+ # - [] of dependencies
16
+ # Usage Example:
17
+ # dependency_modules = get_dependencies(modules)
18
+ def self.get_dependencies(modules)
19
+ dependency_modules = []
20
+ modules.select { |m| m.dependencies_id }.each do |mod|
21
+ mod.dependencies_id.each do |dep|
22
+ dep_module = IrModuleModule.find(:first,
23
+ :domain => [['name', '=', dep.name]],
24
+ :fields => ['id', 'state', 'dependencies_id'])
25
+ if dep_module.nil?
26
+ raise RuntimeError, "#{dep.name} not found"
27
+ end
28
+ dependency_modules << dep_module unless (modules + dependency_modules).map { |m| m.id }.include? dep_module.id
29
+ end
30
+ end
31
+ dependency_modules.concat(get_dependencies(dependency_modules)) if dependency_modules.count > 0
32
+ dependency_modules.uniq { |m| m.id }
33
+ end
34
+
35
+ ##########################################################################
36
+ # Run the upgrade wizard in order to install the required
37
+ # modules. Upgrade installed modules as well.
38
+ # Input :
39
+ # - modules : A [] of valid IrModuleModule instance
40
+ # Return
41
+ # - True
42
+ # Usage Example:
43
+ # res = IrModuleModule.install_modules(@openerp, modules)
44
+ def self.install_modules(openerp, modules, dependencies=false)
45
+ res = true
46
+ if dependencies
47
+ dependency_modules = get_dependencies(modules)
48
+ modules.concat(dependency_modules) if dependency_modules
49
+ end
50
+ modules_toinstall_ids = []
51
+ modules_toupgrade_ids = []
52
+ # If not installed, do it. Otherwise update it
53
+ modules.each do |m|
54
+ if m.state == 'uninstalled'
55
+ m.state = 'to install'
56
+ m.save
57
+ modules_toinstall_ids << m.id
58
+ elsif m.state == 'installed'
59
+ m.state = 'to upgrade'
60
+ m.save
61
+ modules_toupgrade_ids << m.id
62
+ elsif m.state == 'to install'
63
+ modules_toinstall_ids << m.id
64
+ elsif m.state == 'to upgrade'
65
+ modules_toupgrade_ids << m.id
66
+ end
67
+ end
68
+ #First installed required modules, then upgrade the others
69
+ upgrade = BaseModuleUpgrade.create()
70
+ upgrade.upgrade_module()
71
+ # IrModuleModule.button_install(modules_toinstall_ids)
72
+ # IrModuleModule.button_upgrade(modules_toupgrade_ids)
73
+
74
+ if res
75
+ return true
76
+ else
77
+ raise "!!! --- HELPER ERROR : install_modules was unable to install needed modules.."
78
+ end
79
+ openerp.load_models() # reload in order to have model Classes for modules installed
80
+ end
81
+
82
+ def print_uml
83
+ l = IrModelData.find(:all, :domain => {:model=>"ir.model", :module=>name})
84
+ model_names = []
85
+ l.each {|i| model_names << i.name.gsub('_', '.').gsub(/^model.report/, '').gsub(/^model./, '')}
86
+ classes = []
87
+ model_names.each {|i| begin classes << Object.const_get(IrModel.class_name_from_model_key i); rescue; end}
88
+ classes.reject! {|m| m.openerp_model.index("report")} #NOTE we would need a more robust test
89
+ begin
90
+ classes.reject! {|m| IrModel.read(m.openerp_id, ['osv_memory'])['osv_memory']}
91
+ rescue
92
+ end
93
+ classes.reject! {|m| m.openerp_model == "res.company"} if classes.size > 10
94
+ Ooor::UML.print_uml(classes, {:file_name => "#{name}_uml"})
95
+ end
96
+
97
+ def print_dependency_graph
98
+ modules = [self] + self.class.get_dependencies([self])
99
+
100
+ File.open("#{self.name}-pre.dot", 'w') do |f|
101
+ f << <<-eos
102
+ digraph DependenciesByOOOR {
103
+ fontname = "Helvetica"
104
+ fontsize = 11
105
+ label = "*** generated by OOOR by www.akretion.com ***"
106
+ node [
107
+ fontname = "Helvetica"
108
+ fontsize = 11
109
+ shape = "record"
110
+ fillcolor=orange
111
+ style="rounded,filled"
112
+ ]
113
+ eos
114
+
115
+ modules.each do |m|
116
+ m.dependencies_id.each do |dep|
117
+ f << "#{m.name} -> #{dep.name};\n"
118
+ end
119
+ end
120
+ f << "}"
121
+ end
122
+ system("tred < #{self.name}-pre.dot > #{self.name}.dot")
123
+ cmd_line2 = "dot -Tcmapx -o#{self.name}.map -Tpng -o#{self.name}.png #{self.name}.dot"
124
+ system(cmd_line2)
125
+
126
+ end
127
+
128
+ end
129
+
130
+
131
+ Ooor.xtend('ir.ui.menu') do
132
+ def menu_action
133
+ #TODO put in cache eventually:
134
+ action_values = self.class.ooor.const_get('ir.values').rpc_execute('get', 'action', 'tree_but_open', [['ir.ui.menu', id]], false, self.class.ooor.global_context)[0][2]#get already exists
135
+ @menu_action = self.class.ooor.const_get('ir.actions.act_window').new(action_values, []) #TODO deal with action reference instead
136
+ end
137
+ end