ooor 1.1.0 → 1.2.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.
- data/README.md +44 -56
- data/lib/app/models/open_object_resource.rb +157 -113
- data/lib/app/models/open_object_ui.rb +4 -3
- data/lib/app/models/uml.rb +180 -0
- data/lib/ooor.rb +81 -75
- metadata +3 -3
- data/lib/app/controllers/open_objects_controller.rb +0 -139
    
        data/README.md
    CHANGED
    
    | @@ -76,7 +76,7 @@ OOOR also extends ActiveResource a bit with special request parameters (like :do | |
| 76 76 | 
             
            Installation
         | 
| 77 77 | 
             
            ------------
         | 
| 78 78 |  | 
| 79 | 
            -
            You can use OOOR in a standalone (J)Ruby application, or in a Rails application.
         | 
| 79 | 
            +
            You can use OOOR in a standalone (J)Ruby application, or in a Rails application, it only depends on the activeresource gem.
         | 
| 80 80 | 
             
            For both example we assume that you already started some OpenERP server on localhost, with XML/RPC on port 8069 (default),
         | 
| 81 81 | 
             
            with a database called 'mybase', with username 'admin' and password 'admin'.
         | 
| 82 82 |  | 
| @@ -91,8 +91,7 @@ In all case, you first need to install the ooor gem: | |
| 91 91 | 
             
            Let's test OOOR in an irb console (irb command):
         | 
| 92 92 | 
             
                $ require 'rubygems'
         | 
| 93 93 | 
             
                $ require 'ooor'
         | 
| 94 | 
            -
                $  | 
| 95 | 
            -
                $ Ooor.reload!({:url => 'http://localhost:8069/xmlrpc', :database => 'mybase', :username => 'admin', :password => 'admin'})
         | 
| 94 | 
            +
                $ Ooor.new({:url => 'http://localhost:8069/xmlrpc', :database => 'mybase', :username => 'admin', :password => 'admin'})
         | 
| 96 95 | 
             
            This should load all your OpenERP models into Ruby proxy Activeresource objects. Of course there are option to load only some models.
         | 
| 97 96 | 
             
            Let's try to retrieve the user with id 1:
         | 
| 98 97 | 
             
                $ ResUsers.find(1)
         | 
| @@ -116,13 +115,11 @@ You can then use all the OOOR API upon all loaded OpenERP models in your regular | |
| 116 115 | 
             
            A good way to start playing with OOOR is inside the console, using:
         | 
| 117 116 | 
             
                $ ruby script/console #or jruby script/console on JRuby of course
         | 
| 118 117 |  | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
                $ OpenObjectsController.load_all_controllers(map)
         | 
| 122 | 
            -
             | 
| 123 | 
            -
            Or only enable the route to some specific model instead (here partners):
         | 
| 124 | 
            -
                $ map.resources :res_partner
         | 
| 118 | 
            +
            Note: when boostraping Ooor in a Rails application, the default Ooor instance is stored in the OOOR constant.
         | 
| 119 | 
            +
            So for instance you can know all loaded models doing OOOR.all_loaded_models; this is used by [OooREST](http://github.com/rvalyi/ooorest) to register all the REST controllers.
         | 
| 125 120 |  | 
| 121 | 
            +
            Enabling REST HTTP routes to your OpenERP models:
         | 
| 122 | 
            +
            The REST Controller layer of OOOR has been moved as a thin separate gem called [OooREST](http://github.com/rvalyi/ooorest).
         | 
| 126 123 |  | 
| 127 124 |  | 
| 128 125 | 
             
            API usage
         | 
| @@ -140,15 +137,15 @@ Basic finders: | |
| 140 137 | 
             
                $ ProductProduct.find(:last)
         | 
| 141 138 |  | 
| 142 139 |  | 
| 143 | 
            -
            OpenERP domain support:
         | 
| 140 | 
            +
            OpenERP domain support (same as OpenERP):
         | 
| 144 141 |  | 
| 145 142 | 
             
                $ ResPartner.find(:all, :domain=>[['supplier', '=', 1],['active','=',1]])
         | 
| 146 | 
            -
            More  | 
| 143 | 
            +
            More subtle now, remember OpenERP use a kind of inverse polish notation for complex domains,
         | 
| 147 144 | 
             
            here we look for a product in category 1 AND which name is either 'PC1' OR 'PC2':
         | 
| 148 145 | 
             
                $ ProductProduct.find(:all, :domain=>[['categ_id','=',1],'|',['name', '=', 'PC1'],['name','=','PC2']])
         | 
| 149 146 |  | 
| 150 147 |  | 
| 151 | 
            -
            OpenERP context support:
         | 
| 148 | 
            +
            OpenERP context support (same as OpenERP):
         | 
| 152 149 |  | 
| 153 150 | 
             
                $ ProductProduct.find(1, :context => {:my_key => 'value'})
         | 
| 154 151 |  | 
| @@ -166,10 +163,11 @@ Arguments are: domain, offset=0, limit=false, order=false, context={}, count=fal | |
| 166 163 |  | 
| 167 164 | 
             
            Relations (many2one, one2many, many2many) support:
         | 
| 168 165 |  | 
| 169 | 
            -
                $ SaleOrder.find(1).order_line
         | 
| 166 | 
            +
                $ SaleOrder.find(1).order_line #one2many relation
         | 
| 170 167 | 
             
                $ p = ProductProduct.find(1)
         | 
| 171 168 | 
             
                $ p.product_tmpl_id #many2one relation
         | 
| 172 | 
            -
                $ p. | 
| 169 | 
            +
                $ p.taxes_id #automagically reads man2many relation inherited via the product_tmpl_id inheritance relation
         | 
| 170 | 
            +
                $ 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 171 | 
             
                $ p.save #assigns taxes with id 1 and 2 as sale taxes,
         | 
| 174 172 | 
             
            see [the official OpenERP documentation](http://doc.openerp.com/developer/5_18_upgrading_server/19_1_upgrading_server.html?highlight=many2many)
         | 
| 175 173 |  | 
| @@ -180,9 +178,6 @@ Inherited relations support: | |
| 180 178 |  | 
| 181 179 | 
             
            Please notice that loaded relations are cached (to avoid  hitting OpenERP over and over)
         | 
| 182 180 | 
             
            until the root object is reloaded (after save/update for instance).
         | 
| 183 | 
            -
            Currently, save/update doesn't save the whole object graph but only the current object.
         | 
| 184 | 
            -
            We might change this in the future to match the way OpenERP clients are working which
         | 
| 185 | 
            -
            is supported by the OpenERP ORM, see issue: http://github.com/rvalyi/ooor/issues/#issue/3
         | 
| 186 181 |  | 
| 187 182 |  | 
| 188 183 | 
             
            Load only specific fields support (faster than loading all fields):
         | 
| @@ -229,26 +224,48 @@ Call workflow: | |
| 229 224 |  | 
| 230 225 | 
             
            On Change methods:
         | 
| 231 226 |  | 
| 232 | 
            -
             | 
| 233 | 
            -
             | 
| 234 | 
            -
             | 
| 227 | 
            +
            Note: currently OOOR doesn't deal with the View layer, or has a very limited support for forms for the wizards.
         | 
| 228 | 
            +
            So, it's not possible so far for OOOR to know an on_change signature. Because of this, the on_change syntax is  bit awkward
         | 
| 229 | 
            +
            as you will see: you need to explicitely tell the on_change name, the parameter name that changed, the new value and finally
         | 
| 230 | 
            +
            enfore the on_change syntax (looking at the OpenERP model code or view or XML/RPC logs will help you to find out). But
         | 
| 231 | 
            +
            ultimately it works:
         | 
| 232 | 
            +
             | 
| 233 | 
            +
                $ l = SaleOrderLine.new
         | 
| 234 | 
            +
                $ l.on_change('product_id_change', :product_id, 20, 1, 20, 1, false, 1, false, false, 7, 'en_US', true, false, false, false)
         | 
| 235 | 
            +
                $ => #<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}>
         | 
| 235 236 | 
             
            Notice that it reloads the Objects attrs and print warning message accordingly
         | 
| 236 237 |  | 
| 237 238 |  | 
| 239 | 
            +
            On the fly one2many object graph update/creation:
         | 
| 240 | 
            +
             | 
| 241 | 
            +
            Just like the OpenERP GTK client (and unlike the web client), in OOOR you can pass create/update
         | 
| 242 | 
            +
            one2many relation in place directly. For instance:
         | 
| 243 | 
            +
                $ so = SaleOrder.new
         | 
| 244 | 
            +
                $ so.on_change('onchange_partner_id', :partner_id, 1, 1, false) #auto-complete the address and other data based on the partner
         | 
| 245 | 
            +
                $ so.order_line = [SaleOrderLine.new(:name => 'sl1', :product_id => 1, :price_unit => 42, :product_uom => 1)] #create one order line
         | 
| 246 | 
            +
                $ so.save
         | 
| 247 | 
            +
                $ so.amount_total
         | 
| 248 | 
            +
                $ => 42.0
         | 
| 249 | 
            +
             | 
| 250 | 
            +
             | 
| 238 251 | 
             
            Call aribtrary method:
         | 
| 239 252 |  | 
| 240 253 | 
             
                $ use static ObjectClass.rpc_execute_with_all method
         | 
| 241 254 | 
             
                $ or object.call(method_name, args*) #were args is an aribtrary list of arguments
         | 
| 242 | 
            -
             | 
| 255 | 
            +
             | 
| 256 | 
            +
            Class methods from are osv.py/orm.py proxied to OpenERP directly (as the web client does):
         | 
| 243 257 | 
             
                $ ResPartner.name_search('ax', [], 'ilike', {})
         | 
| 244 258 | 
             
                $ ProductProduct.fields_view_get(132, 'tree', {})
         | 
| 245 259 |  | 
| 246 260 |  | 
| 247 | 
            -
            Call old wizards:
         | 
| 261 | 
            +
            Call old style wizards:
         | 
| 248 262 |  | 
| 249 263 | 
             
                $ inv = AccountInvoice.find(4)
         | 
| 264 | 
            +
                $ #in case the inv.state is 'draft', do inv.wkf_action('invoice_open')
         | 
| 250 265 | 
             
                $ wizard = inv.old_wizard_step('account.invoice.pay') #tip: you can inspect the wizard fields, arch and datas
         | 
| 251 266 | 
             
                $ wizard.reconcile({:journal_id => 6, :name =>"from_rails"}) #if you want to pay all; will give you a reloaded invoice
         | 
| 267 | 
            +
                $ inv.state
         | 
| 268 | 
            +
                $ => "paid"
         | 
| 252 269 | 
             
                $ #or if you want a payment with a write off:
         | 
| 253 270 | 
             
                $ wizard.writeoff_check({"amount" => 12, "journal_id" => 6, "name" =>'from_rails'}) #use the button name as the wizard method
         | 
| 254 271 | 
             
                $ wizard.reconcile({required missing write off fields...}) #will give you a reloaded invoice because state is 'end'
         | 
| @@ -274,21 +291,7 @@ However you might want to change that. 2 solutions: | |
| 274 291 | 
             
                $ In the config yaml file or hash, set the :log_level parameter
         | 
| 275 292 |  | 
| 276 293 |  | 
| 277 | 
            -
             | 
| 278 | 
            -
            REST HTTP API:
         | 
| 279 | 
            -
             | 
| 280 | 
            -
                $ http://localhost:3000/res_partner
         | 
| 281 | 
            -
                $ http://localhost:3000/res_partner.xml
         | 
| 282 | 
            -
                $ http://localhost:3000/res_partner.json
         | 
| 283 | 
            -
                $ http://localhost:3000/res_partner/2
         | 
| 284 | 
            -
                $ http://localhost:3000/res_partner/2.json
         | 
| 285 | 
            -
                $ http://localhost:3000/res_partner/2.xml
         | 
| 286 | 
            -
                $ http://localhost:3000/res_partner/[2,3,4].xml
         | 
| 287 | 
            -
                $ http://localhost:3000/res_partner/[2,3,4].json
         | 
| 288 | 
            -
             | 
| 289 | 
            -
                $ TODO http://localhost:3000/res_partner.xml?active=1
         | 
| 290 | 
            -
             | 
| 291 | 
            -
                $ TODO http://localhost:3000/res_partner.xml?domain=TODO
         | 
| 294 | 
            +
            [Drawing OpenERP UML diagrams with OOOR](http://wiki.github.com/rvalyi/ooor/drawing-openerp-uml-diagrams-with-ooor)
         | 
| 292 295 |  | 
| 293 296 |  | 
| 294 297 | 
             
            FAQ
         | 
| @@ -302,17 +305,16 @@ Then create indents in the log before doing some action and watch your logs care | |
| 302 305 |  | 
| 303 306 | 
             
            ### How can I load/reload my OpenERP models into my Ruby application?
         | 
| 304 307 |  | 
| 305 | 
            -
            You can load/reload your models at any time (even in console),  | 
| 306 | 
            -
                $ Ooor. | 
| 308 | 
            +
            You can load/reload your models at any time (even in console), creating a new Ooor instance that will override the class definitions:
         | 
| 309 | 
            +
                $ Ooor.new({:url => 'http://localhost:8069/xmlrpc', :database => 'mybase', :username => 'admin', :password => 'admin'})
         | 
| 307 310 | 
             
            or using a config YAML file instead:
         | 
| 308 | 
            -
                $ Ooor. | 
| 311 | 
            +
                $ Ooor.new("config/ooor.yml")
         | 
| 309 312 |  | 
| 310 313 | 
             
            ### Do I need to load all the OpenERP models in my Ruby application?
         | 
| 311 314 |  | 
| 312 315 | 
             
            You can load only some OpenERP models (not all), which is faster and better in term of memory/security:
         | 
| 313 316 | 
             
                $ Ooor.reload!({:models => [res.partner, product.template, product.product], :url => 'http://localhost:8069/xmlrpc', :database => 'mybase', :username => 'admin', :password => 'admin'})
         | 
| 314 317 |  | 
| 315 | 
            -
             | 
| 316 318 | 
             
            ### Isn't OOOR slow?
         | 
| 317 319 |  | 
| 318 320 | 
             
            You might think that proxying a Python based server through a Rails app using XML/RPC would be dog slow. Well, not too much actually.
         | 
| @@ -338,18 +340,4 @@ In you app/model directory, create a product_product.rb file with inside, the re | |
| 338 340 | 
             
                $   end
         | 
| 339 341 | 
             
                $ end
         | 
| 340 342 |  | 
| 341 | 
            -
            Now a ProductProduct resource got a method foo, returning "bar".
         | 
| 342 | 
            -
             | 
| 343 | 
            -
            ### Can I extend the OOOR controllers?
         | 
| 344 | 
            -
             | 
| 345 | 
            -
            Yes, you can do that, see the "how to extends models" section as it's very similar. Instead, in the app/controllers directory, you'll re-open defined controllers,
         | 
| 346 | 
            -
            for the product.product controllers, it means creating a product_product_controller.rb file with:
         | 
| 347 | 
            -
             | 
| 348 | 
            -
                $ class ProductProduct < OpenObjectsController
         | 
| 349 | 
            -
                $   def foo
         | 
| 350 | 
            -
                $     render :text => "bar"
         | 
| 351 | 
            -
                $   end
         | 
| 352 | 
            -
                $ end
         | 
| 353 | 
            -
             | 
| 354 | 
            -
            Now, if you register that new method in your route.rb file GET /product_product/1/foo will render "bar" on your browser screen.
         | 
| 355 | 
            -
            You could instead just customize the existing CRUD methods so you don't need to regiter any other route in route.rb.
         | 
| 343 | 
            +
            Now a ProductProduct resource got a method foo, returning "bar".
         | 
| @@ -1,30 +1,29 @@ | |
| 1 1 | 
             
            require 'xmlrpc/client'
         | 
| 2 | 
            -
            require ' | 
| 2 | 
            +
            require 'active_resource'
         | 
| 3 3 | 
             
            require 'app/models/open_object_ui'
         | 
| 4 | 
            +
            require 'app/models/uml'
         | 
| 4 5 |  | 
| 5 6 | 
             
            #TODO implement passing session credentials to RPC methods (concurrent access of different user credentials in Rails)
         | 
| 6 7 |  | 
| 7 8 | 
             
            class OpenObjectResource < ActiveResource::Base
         | 
| 9 | 
            +
              include UML
         | 
| 8 10 |  | 
| 9 11 | 
             
              # ******************** class methods ********************
         | 
| 10 12 | 
             
              class << self
         | 
| 11 13 |  | 
| 12 14 | 
             
                cattr_accessor :logger
         | 
| 13 15 | 
             
                attr_accessor :openerp_id, :info, :access_ids, :name, :openerp_model, :field_ids, :state, #model class attributes assotiated to the OpenERP ir.model
         | 
| 14 | 
            -
                              : | 
| 15 | 
            -
                              :openerp_database, :user_id
         | 
| 16 | 
            +
                              :fields, :fields_defined, :many2one_relations, :one2many_relations, :many2many_relations,
         | 
| 17 | 
            +
                              :openerp_database, :user_id, :scope_prefix, :ooor
         | 
| 16 18 |  | 
| 17 | 
            -
                def class_name_from_model_key(model_key)
         | 
| 18 | 
            -
                  model_key.split('.').collect {|name_part| name_part | 
| 19 | 
            +
                def class_name_from_model_key(model_key=self.openerp_model)
         | 
| 20 | 
            +
                  self.scope_prefix + model_key.split('.').collect {|name_part| name_part.capitalize}.join
         | 
| 19 21 | 
             
                end
         | 
| 20 22 |  | 
| 21 23 | 
             
                def reload_fields_definition(force = false)
         | 
| 22 | 
            -
                  if self | 
| 23 | 
            -
                    fields = IrModelFields.find(@field_ids)
         | 
| 24 | 
            +
                  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
         | 
| 25 | 
            +
                    fields = Object.const_get(self.scope_prefix + 'IrModelFields').find(@field_ids)
         | 
| 24 26 | 
             
                    @fields = {}
         | 
| 25 | 
            -
                    @many2one_relations = {}
         | 
| 26 | 
            -
                    @one2many_relations = {}
         | 
| 27 | 
            -
                    @many2many_relations = {}
         | 
| 28 27 | 
             
                    fields.each do |field|
         | 
| 29 28 | 
             
                      case field.attributes['ttype']
         | 
| 30 29 | 
             
                      when 'many2one'
         | 
| @@ -37,38 +36,11 @@ class OpenObjectResource < ActiveResource::Base | |
| 37 36 | 
             
                        @fields[field.attributes['name']] = field
         | 
| 38 37 | 
             
                      end
         | 
| 39 38 | 
             
                    end
         | 
| 40 | 
            -
                    logger.info "#{fields.size} fields loaded"
         | 
| 39 | 
            +
                    logger.info "#{fields.size} fields loaded in model #{self.class}"
         | 
| 41 40 | 
             
                  end
         | 
| 42 | 
            -
                  @ | 
| 41 | 
            +
                  @fields_defined = true
         | 
| 43 42 | 
             
                end
         | 
| 44 43 |  | 
| 45 | 
            -
                def define_openerp_model(arg, url, database, user_id, pass, binding)
         | 
| 46 | 
            -
                  param = (arg.is_a? OpenObjectResource) ? arg.attributes.merge(arg.relations) : {'model' => arg}
         | 
| 47 | 
            -
                  model_key = param['model']
         | 
| 48 | 
            -
                  Ooor.all_loaded_models.push(model_key)
         | 
| 49 | 
            -
                  model_class_name = class_name_from_model_key(model_key)
         | 
| 50 | 
            -
                  logger.info "registering #{model_class_name} as a Rails ActiveResource Model wrapper for OpenObject #{model_key} model"
         | 
| 51 | 
            -
                  definition = "
         | 
| 52 | 
            -
                  class #{model_class_name} < OpenObjectResource
         | 
| 53 | 
            -
                    self.site = '#{url || Ooor.base_url}'
         | 
| 54 | 
            -
                    self.user = #{user_id}
         | 
| 55 | 
            -
                    self.password = #{pass || false}
         | 
| 56 | 
            -
                    self.openerp_database = '#{database}'
         | 
| 57 | 
            -
                    self.openerp_model = '#{model_key}'
         | 
| 58 | 
            -
                    self.openerp_id = #{param['id'] || false}
         | 
| 59 | 
            -
                    self.info = '#{(param['info'] || '').gsub("'",' ')}'
         | 
| 60 | 
            -
                    self.name = '#{param['name']}'
         | 
| 61 | 
            -
                    self.state = '#{param['state']}'
         | 
| 62 | 
            -
                    self.field_ids = #{(param['field_id'] and '[' + param['field_id'].join(',') + ']') || false}
         | 
| 63 | 
            -
                    self.access_ids = #{(param['access_ids'] and '[' + param['access_ids'].join(',') + ']') || false}
         | 
| 64 | 
            -
                    self.many2one_relations = {}
         | 
| 65 | 
            -
                    self.one2many_relations = {}
         | 
| 66 | 
            -
                    self.many2many_relations = {}
         | 
| 67 | 
            -
                  end"
         | 
| 68 | 
            -
                  eval definition, binding
         | 
| 69 | 
            -
                end
         | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 44 | 
             
                # ******************** remote communication ********************
         | 
| 73 45 |  | 
| 74 46 | 
             
                #OpenERP search method
         | 
| @@ -78,12 +50,7 @@ class OpenObjectResource < ActiveResource::Base | |
| 78 50 |  | 
| 79 51 | 
             
                def client(url)
         | 
| 80 52 | 
             
                  @clients ||= {}
         | 
| 81 | 
            -
                  @ | 
| 82 | 
            -
                  unless @clientl
         | 
| 83 | 
            -
                    @client ||= XMLRPC::Client.new2(url)
         | 
| 84 | 
            -
                    @clients[url] = @client
         | 
| 85 | 
            -
                  end
         | 
| 86 | 
            -
                  return @client
         | 
| 53 | 
            +
                  @clients[url] ||= XMLRPC::Client.new2(url)
         | 
| 87 54 | 
             
                end
         | 
| 88 55 |  | 
| 89 56 | 
             
                #corresponding method for OpenERP osv.execute(self, db, uid, obj, method, *args, **kw) method
         | 
| @@ -92,16 +59,16 @@ class OpenObjectResource < ActiveResource::Base | |
| 92 59 | 
             
                end
         | 
| 93 60 |  | 
| 94 61 | 
             
                def rpc_execute_with_object(object, method, *args)
         | 
| 95 | 
            -
                  rpc_execute_with_all(@database ||  | 
| 62 | 
            +
                  rpc_execute_with_all(@database || @ooor.config[:database], @user_id || @ooor.config[:user_id], @password || @ooor.config[:password], object, method, *args)
         | 
| 96 63 | 
             
                end
         | 
| 97 64 |  | 
| 98 65 | 
             
                #corresponding method for OpenERP osv.execute(self, db, uid, obj, method, *args, **kw) method
         | 
| 99 66 | 
             
                def rpc_execute_with_all(db, uid, pass, obj, method, *args)
         | 
| 100 67 | 
             
                  if args[-1].is_a? Hash
         | 
| 101 | 
            -
                    args[-1] =  | 
| 68 | 
            +
                    args[-1] = @ooor.global_context.merge(args[-1])
         | 
| 102 69 | 
             
                  end
         | 
| 103 70 | 
             
                  logger.debug "rpc_execute_with_all: rpc_methods: 'execute', db: #{db.inspect}, uid: #{uid.inspect}, pass: #{pass.inspect}, obj: #{obj.inspect}, method: #{method}, *args: #{args.inspect}"
         | 
| 104 | 
            -
                  try_with_pretty_error_log { client((@database && @site ||  | 
| 71 | 
            +
                  try_with_pretty_error_log { client((@database && @site || @ooor.base_url) + "/object").call("execute",  db, uid, pass, obj, method, *args) }
         | 
| 105 72 | 
             
                end
         | 
| 106 73 |  | 
| 107 74 | 
             
                 #corresponding method for OpenERP osv.exec_workflow(self, db, uid, obj, method, *args)
         | 
| @@ -110,23 +77,23 @@ class OpenObjectResource < ActiveResource::Base | |
| 110 77 | 
             
                end
         | 
| 111 78 |  | 
| 112 79 | 
             
                def rpc_exec_workflow_with_object(object, action, *args)
         | 
| 113 | 
            -
                  rpc_exec_workflow_with_all(@database ||  | 
| 80 | 
            +
                  rpc_exec_workflow_with_all(@database || @ooor.config[:database], @user_id || @ooor.config[:user_id], @password || @ooor.config[:password], object, action, *args)
         | 
| 114 81 | 
             
                end
         | 
| 115 82 |  | 
| 116 83 | 
             
                def rpc_exec_workflow_with_all(db, uid, pass, obj, action, *args)
         | 
| 117 84 | 
             
                  if args[-1].is_a? Hash
         | 
| 118 | 
            -
                    args[-1] =  | 
| 85 | 
            +
                    args[-1] = @ooor.global_context.merge(args[-1])
         | 
| 119 86 | 
             
                  end
         | 
| 120 87 | 
             
                  logger.debug "rpc_execute_with_all: rpc_methods: 'exec_workflow', db: #{db.inspect}, uid: #{uid.inspect}, pass: #{pass.inspect}, obj: #{obj.inspect}, action #{action}, *args: #{args.inspect}"
         | 
| 121 | 
            -
                  try_with_pretty_error_log { client((@database && @site ||  | 
| 88 | 
            +
                  try_with_pretty_error_log { client((@database && @site || @ooor.base_url) + "/object").call("exec_workflow", db, uid, pass, obj, action, *args) }
         | 
| 122 89 | 
             
                end
         | 
| 123 90 |  | 
| 124 91 | 
             
                def old_wizard_step(wizard_name, ids, step='init', wizard_id=nil, form={}, context={}, report_type='pdf')
         | 
| 125 | 
            -
                  context =  | 
| 92 | 
            +
                  context = @ooor.global_context.merge(context)
         | 
| 126 93 | 
             
                  unless wizard_id
         | 
| 127 | 
            -
                    wizard_id = try_with_pretty_error_log { client((@database && @site ||  | 
| 94 | 
            +
                    wizard_id = try_with_pretty_error_log { client((@database && @site || @ooor.base_url) + "/wizard").call("create",  @database || @ooor.config[:database], @user_id || @ooor.config[:user_id], @password || @ooor.config[:password], wizard_name) }
         | 
| 128 95 | 
             
                  end
         | 
| 129 | 
            -
                  [wizard_id, try_with_pretty_error_log { client((@database && @site ||  | 
| 96 | 
            +
                  [wizard_id, try_with_pretty_error_log { client((@database && @site || @ooor.base_url) + "/wizard").call("execute",  @database || @ooor.config[:database], @user_id || @ooor.config[:user_id], @password || @ooor.config[:password], wizard_id, {'model' => @openerp_model, 'form' => form, 'id' => ids[0], 'report_type' => report_type, 'ids' => ids}, step, context) }]
         | 
| 130 97 | 
             
                end
         | 
| 131 98 |  | 
| 132 99 | 
             
                #grab the eventual error log from OpenERP response as OpenERP doesn't enforce carefuly
         | 
| @@ -146,17 +113,13 @@ class OpenObjectResource < ActiveResource::Base | |
| 146 113 | 
             
                    raise
         | 
| 147 114 | 
             
                end
         | 
| 148 115 |  | 
| 149 | 
            -
                def method_missing(method_symbol, *arguments)
         | 
| 150 | 
            -
                  return self.rpc_execute(method_symbol.to_s, *arguments)
         | 
| 151 | 
            -
                end
         | 
| 116 | 
            +
                def method_missing(method_symbol, *arguments) return self.rpc_execute(method_symbol.to_s, *arguments) end
         | 
| 152 117 |  | 
| 153 | 
            -
                def load_relation(model_key, ids, *arguments)
         | 
| 118 | 
            +
                def load_relation(model_key, ids, scope_prefix, *arguments)
         | 
| 154 119 | 
             
                  options = arguments.extract_options!
         | 
| 155 | 
            -
                   | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
                  end
         | 
| 159 | 
            -
                  relation_model_class = eval class_name_from_model_key(model_key)
         | 
| 120 | 
            +
                  class_name = class_name_from_model_key(model_key)
         | 
| 121 | 
            +
                  @ooor.define_openerp_model(model_key, nil, nil, nil, nil, scope_prefix) unless Object.const_defined?(class_name)
         | 
| 122 | 
            +
                  relation_model_class = Object.const_get(class_name)
         | 
| 160 123 | 
             
                  relation_model_class.send :find, ids, :fields => options[:fields] || [], :context => options[:context] || {}
         | 
| 161 124 | 
             
                end
         | 
| 162 125 |  | 
| @@ -180,9 +143,7 @@ class OpenObjectResource < ActiveResource::Base | |
| 180 143 | 
             
                end
         | 
| 181 144 |  | 
| 182 145 | 
             
                #TODO, make sense?
         | 
| 183 | 
            -
                def find_one
         | 
| 184 | 
            -
                  raise "Not implemented yet, go on!"
         | 
| 185 | 
            -
                end
         | 
| 146 | 
            +
                def find_one; raise"Not implemented yet, go on!"; end
         | 
| 186 147 |  | 
| 187 148 | 
             
                # Find a single resource from the default URL
         | 
| 188 149 | 
             
                def find_single(scope, options)
         | 
| @@ -216,28 +177,87 @@ class OpenObjectResource < ActiveResource::Base | |
| 216 177 |  | 
| 217 178 | 
             
              attr_accessor :relations, :loaded_relations
         | 
| 218 179 |  | 
| 219 | 
            -
              def  | 
| 220 | 
            -
                @attributes.each  | 
| 180 | 
            +
              def cast_attributes_to_ruby!
         | 
| 181 | 
            +
                @attributes.each do |k, v|
         | 
| 182 | 
            +
                  if self.class.fields[k]
         | 
| 183 | 
            +
                    if v.is_a?(String)
         | 
| 184 | 
            +
                      case self.class.fields[k].ttype
         | 
| 185 | 
            +
                        when 'datetime'
         | 
| 186 | 
            +
                          @attributes[k] = Time.parse(v)
         | 
| 187 | 
            +
                        when 'date'
         | 
| 188 | 
            +
                          @attributes[k] = Date.parse(v)
         | 
| 189 | 
            +
                      end
         | 
| 190 | 
            +
                    end
         | 
| 191 | 
            +
                  end
         | 
| 192 | 
            +
                end
         | 
| 221 193 | 
             
              end
         | 
| 222 194 |  | 
| 223 | 
            -
              def  | 
| 224 | 
            -
                 | 
| 195 | 
            +
              def cast_attributes_to_openerp!
         | 
| 196 | 
            +
                @attributes.each do |k, v|
         | 
| 197 | 
            +
                  @attributes[k] = ((v.is_a? BigDecimal) ? Float(v) : v)
         | 
| 198 | 
            +
                  if self.class.fields[k]
         | 
| 199 | 
            +
                    case self.class.fields[k].ttype
         | 
| 200 | 
            +
                      when 'datetime'
         | 
| 201 | 
            +
                        @attributes[k] = "#{v.year}-#{v.month}-#{v.day} #{v.hour}:#{v.min}:#{v.sec}" if v.respond_to?(:sec)
         | 
| 202 | 
            +
                      when 'date'
         | 
| 203 | 
            +
                        @attributes[k] = "#{v.year}-#{v.month}-#{v.day}" if v.is_a?(Date)
         | 
| 204 | 
            +
                    end
         | 
| 205 | 
            +
                  end
         | 
| 206 | 
            +
                end
         | 
| 207 | 
            +
              end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
              def cast_relations_to_openerp!
         | 
| 210 | 
            +
                @relations.reject! do |k, v| #reject non asigned many2one or empty list
         | 
| 211 | 
            +
                  v.is_a?(Array) && (v.size == 0 or v[1].is_a?(String))
         | 
| 212 | 
            +
                end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                def cast_relation(k, v, one2many_relations, many2many_relations)
         | 
| 215 | 
            +
                  if one2many_relations[k]
         | 
| 216 | 
            +
                    return v.collect! do |value|
         | 
| 217 | 
            +
                      if value.is_a?(OpenObjectResource) #on the fly creation as in the GTK client
         | 
| 218 | 
            +
                        [0, 0, value.to_openerp_hash!]
         | 
| 219 | 
            +
                      else
         | 
| 220 | 
            +
                        [1, value, {}]
         | 
| 221 | 
            +
                      end
         | 
| 222 | 
            +
                    end
         | 
| 223 | 
            +
                  elsif many2many_relations[k]
         | 
| 224 | 
            +
                    return v = [[6, 0, v]]
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
                end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                @relations.each do |k, v| #see OpenERP awkward relations API
         | 
| 229 | 
            +
                  new_rel = self.cast_relation(k, v, self.class.one2many_relations, self.class.many2many_relations)
         | 
| 230 | 
            +
                  if new_rel #matches a known o2m or m2m
         | 
| 231 | 
            +
                    @relations[k] = new_rel
         | 
| 232 | 
            +
                  else
         | 
| 233 | 
            +
                    self.class.many2one_relations.each do |k2, field| #try to cast the relation to na inherited o2m or m2m:
         | 
| 234 | 
            +
                      class_name = self.class.class_name_from_model_key(field.relation)
         | 
| 235 | 
            +
                      self.class.ooor.define_openerp_model(field.relation, nil, nil, nil, nil, self.class.scope_prefix) unless Object.const_defined?(class_name)
         | 
| 236 | 
            +
                      linked_class = Object.const_get(class_name)
         | 
| 237 | 
            +
                      linked_class.reload_fields_definition unless linked_class.fields_defined
         | 
| 238 | 
            +
                      new_rel = self.cast_relation(k, v, linked_class.one2many_relations, linked_class.many2many_relations)
         | 
| 239 | 
            +
                      @relations[k] = new_rel and break if new_rel
         | 
| 240 | 
            +
                    end
         | 
| 241 | 
            +
                  end
         | 
| 242 | 
            +
                end
         | 
| 225 243 | 
             
              end
         | 
| 226 244 |  | 
| 245 | 
            +
              def reload_from_record!(record) load(record.attributes, record.relations) end
         | 
| 246 | 
            +
             | 
| 227 247 | 
             
              def load(attributes, relations={})
         | 
| 228 | 
            -
                self.class.reload_fields_definition unless self.class. | 
| 248 | 
            +
                self.class.reload_fields_definition() unless self.class.fields_defined
         | 
| 229 249 | 
             
                raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
         | 
| 230 250 | 
             
                @prefix_options, attributes = split_options(attributes)
         | 
| 231 251 | 
             
                @relations = relations
         | 
| 252 | 
            +
                @attributes = {}
         | 
| 232 253 | 
             
                @loaded_relations = {}
         | 
| 233 254 | 
             
                attributes.each do |key, value|
         | 
| 234 255 | 
             
                  skey = key.to_s
         | 
| 235 | 
            -
                  if self.class.many2one_relations.has_key?(skey) || self.class.one2many_relations.has_key?(skey) || | 
| 256 | 
            +
                  if self.class.many2one_relations.has_key?(skey) || self.class.one2many_relations.has_key?(skey) ||
         | 
| 257 | 
            +
                     self.class.many2many_relations.has_key?(skey) || value.is_a?(Array)
         | 
| 236 258 | 
             
                    relations[skey] = value #the relation because we want the method to load the association through method missing
         | 
| 237 259 | 
             
                  else
         | 
| 238 260 | 
             
                    case value
         | 
| 239 | 
            -
                      when self.class.many2one_relations.has_key?(skey) || self.class.one2many_relations.has_key?(skey) || self.class.many2many_relations.has_key?(skey)
         | 
| 240 | 
            -
                         relations[skey] = value #the relation because we want the method to load the association through method missing
         | 
| 241 261 | 
             
                      when Hash
         | 
| 242 262 | 
             
                        resource = find_or_create_resource_for(key) #TODO check!
         | 
| 243 263 | 
             
                        @attributes[skey] = resource@attributes[skey].new(value)
         | 
| @@ -246,25 +266,40 @@ class OpenObjectResource < ActiveResource::Base | |
| 246 266 | 
             
                    end
         | 
| 247 267 | 
             
                  end
         | 
| 248 268 | 
             
                end
         | 
| 249 | 
            -
             | 
| 269 | 
            +
                cast_attributes_to_ruby!
         | 
| 250 270 | 
             
                self
         | 
| 251 271 | 
             
              end
         | 
| 252 272 |  | 
| 253 | 
            -
               | 
| 273 | 
            +
              def display_available_fields
         | 
| 274 | 
            +
                self.class.logger.debug ""
         | 
| 275 | 
            +
                self.class.logger.debug "*** DIRECTLY AVAILABLE FIELDS ON OBJECT #{self} ARE: ***\n"
         | 
| 276 | 
            +
                self.class.fields.sort {|a,b| a[1].ttype<=>b[1].ttype}.each {|i| self.class.logger.debug "#{i[1].ttype} --- #{i[0]}"}
         | 
| 277 | 
            +
                self.class.logger.debug ""
         | 
| 278 | 
            +
                self.class.many2one_relations.each {|k, v| self.class.logger.debug "many2one --- #{v.relation} --- #{k}"}
         | 
| 279 | 
            +
                self.class.logger.debug ""
         | 
| 280 | 
            +
                self.class.one2many_relations.each {|k, v| self.class.logger.debug "one2many --- #{v.relation} --- #{k}"}
         | 
| 281 | 
            +
                self.class.logger.debug ""
         | 
| 282 | 
            +
                self.class.many2many_relations.each {|k, v| self.class.logger.debug "many2many --- #{v.relation} --- #{k}"}
         | 
| 283 | 
            +
                self.class.logger.debug ""
         | 
| 284 | 
            +
                self.class.logger.debug "YOU CAN ALSO USE THE INHERITED FIELDS FROM THE INHERITANCE MANY2ONE RELATIONS OR THE OBJECT METHODS..."
         | 
| 285 | 
            +
                self.class.logger.debug ""
         | 
| 286 | 
            +
              end
         | 
| 287 | 
            +
             | 
| 288 | 
            +
              def to_openerp_hash!
         | 
| 289 | 
            +
                cast_attributes_to_openerp!
         | 
| 290 | 
            +
                cast_relations_to_openerp!
         | 
| 291 | 
            +
                @attributes.reject {|key, value| key == 'id'}.merge(@relations)
         | 
| 292 | 
            +
              end
         | 
| 293 | 
            +
             | 
| 294 | 
            +
              #compatible with the Rails way but also supports OpenERP context
         | 
| 254 295 | 
             
              def create(context={})
         | 
| 255 | 
            -
                self. | 
| 256 | 
            -
                m2o = @relations.reject{|k, v| !self.class.many2one_relations.has_key?(k)}
         | 
| 257 | 
            -
                vals = @attributes.merge(m2o.merge(m2o){|k, v| v.is_a?(Array) ? v[0] : v})
         | 
| 258 | 
            -
                self.id = self.class.rpc_execute('create', vals, context)
         | 
| 296 | 
            +
                self.id = self.class.rpc_execute('create', to_openerp_hash!, context)
         | 
| 259 297 | 
             
                reload_from_record!(self.class.find(self.id, :context => context))
         | 
| 260 298 | 
             
              end
         | 
| 261 299 |  | 
| 262 | 
            -
              #compatible with the Rails way but also supports OpenERP context | 
| 300 | 
            +
              #compatible with the Rails way but also supports OpenERP context
         | 
| 263 301 | 
             
              def update(context={})
         | 
| 264 | 
            -
                self. | 
| 265 | 
            -
                m2o = @relations.reject{|k, v| !self.class.many2one_relations.has_key?(k)}
         | 
| 266 | 
            -
                vals = @attributes.reject {|key, value| key == 'id'}.merge(m2o.merge(m2o){|k, v| v.is_a?(Array) ? v[0] : v})
         | 
| 267 | 
            -
                self.class.rpc_execute('write', self.id, vals, context)
         | 
| 302 | 
            +
                self.class.rpc_execute('write', self.id, to_openerp_hash!, context)
         | 
| 268 303 | 
             
                reload_from_record!(self.class.find(self.id, :context => context))
         | 
| 269 304 | 
             
              end
         | 
| 270 305 |  | 
| @@ -274,21 +309,21 @@ class OpenObjectResource < ActiveResource::Base | |
| 274 309 | 
             
              end
         | 
| 275 310 |  | 
| 276 311 | 
             
              #OpenERP copy method, load persisted copied Object
         | 
| 277 | 
            -
              def copy(defaults= | 
| 312 | 
            +
              def copy(defaults={}, context={})
         | 
| 278 313 | 
             
                self.class.find(self.class.rpc_execute('copy', self.id, defaults, context), :context => context)
         | 
| 279 314 | 
             
              end
         | 
| 280 315 |  | 
| 281 316 | 
             
              #Generic OpenERP rpc method call
         | 
| 282 | 
            -
              def call(method, *args)
         | 
| 283 | 
            -
                self.class.rpc_execute(method, *args)
         | 
| 284 | 
            -
              end
         | 
| 317 | 
            +
              def call(method, *args) self.class.rpc_execute(method, *args) end
         | 
| 285 318 |  | 
| 286 319 | 
             
              #Generic OpenERP on_change method
         | 
| 287 | 
            -
              def on_change(on_change_method, *args)
         | 
| 288 | 
            -
                result = self.class.rpc_execute(on_change_method, *args)
         | 
| 289 | 
            -
                 | 
| 290 | 
            -
             | 
| 291 | 
            -
             | 
| 320 | 
            +
              def on_change(on_change_method, field_name, field_value, *args)
         | 
| 321 | 
            +
                result = self.class.rpc_execute(on_change_method, self.id && [id] || [], *args)
         | 
| 322 | 
            +
                if result["warning"]
         | 
| 323 | 
            +
                  self.class.logger.info result["warning"]["title"]
         | 
| 324 | 
            +
                  self.class.logger.info result["warning"]["message"]
         | 
| 325 | 
            +
                end
         | 
| 326 | 
            +
                load({field_name => field_value}.merge(result["value"]))
         | 
| 292 327 | 
             
              end
         | 
| 293 328 |  | 
| 294 329 | 
             
              #wrapper for OpenERP exec_workflow Business Process Management engine
         | 
| @@ -299,20 +334,20 @@ class OpenObjectResource < ActiveResource::Base | |
| 299 334 |  | 
| 300 335 | 
             
              def old_wizard_step(wizard_name, step='init', wizard_id=nil, form={}, context={})
         | 
| 301 336 | 
             
                result = self.class.old_wizard_step(wizard_name, [self.id], step, wizard_id, form, {})
         | 
| 302 | 
            -
                OpenObjectWizard.new(wizard_name, result[0], result[1], [self])
         | 
| 337 | 
            +
                OpenObjectWizard.new(wizard_name, result[0], result[1], [self], self.class.ooor.global_context)
         | 
| 303 338 | 
             
              end
         | 
| 304 339 |  | 
| 305 340 |  | 
| 306 341 | 
             
              # ******************** fake associations like much like ActiveRecord according to the cached OpenERP data model ********************
         | 
| 307 342 |  | 
| 308 343 | 
             
              def relationnal_result(method_name, *arguments)
         | 
| 309 | 
            -
                self.class.reload_fields_definition unless self.class. | 
| 344 | 
            +
                self.class.reload_fields_definition unless self.class.fields_defined
         | 
| 310 345 | 
             
                if self.class.many2one_relations.has_key?(method_name)
         | 
| 311 | 
            -
                  self.class.load_relation(self.class.many2one_relations[method_name].relation, @relations[method_name][0], *arguments)
         | 
| 346 | 
            +
                  self.class.load_relation(self.class.many2one_relations[method_name].relation, @relations[method_name][0], self.class.scope_prefix, *arguments)
         | 
| 312 347 | 
             
                elsif self.class.one2many_relations.has_key?(method_name)
         | 
| 313 | 
            -
                  self.class.load_relation(self.class.one2many_relations[method_name].relation, @relations[method_name], *arguments)
         | 
| 348 | 
            +
                  self.class.load_relation(self.class.one2many_relations[method_name].relation, @relations[method_name], self.class.scope_prefix, *arguments)
         | 
| 314 349 | 
             
                elsif self.class.many2many_relations.has_key?(method_name)
         | 
| 315 | 
            -
                  self.class.load_relation(self.class.many2many_relations[method_name].relation, @relations[method_name], *arguments)
         | 
| 350 | 
            +
                  self.class.load_relation(self.class.many2many_relations[method_name].relation, @relations[method_name], self.class.scope_prefix, *arguments)
         | 
| 316 351 | 
             
                else
         | 
| 317 352 | 
             
                  false
         | 
| 318 353 | 
             
                end
         | 
| @@ -320,24 +355,33 @@ class OpenObjectResource < ActiveResource::Base | |
| 320 355 |  | 
| 321 356 | 
             
              def method_missing(method_symbol, *arguments)
         | 
| 322 357 | 
             
                method_name = method_symbol.to_s
         | 
| 358 | 
            +
                return super if attributes.has_key?(method_name) or attributes.has_key?(method_name.first(-1))
         | 
| 359 | 
            +
                if method_name.end_with?('=')
         | 
| 360 | 
            +
                  @relations[method_name.sub('=', '')] = *arguments
         | 
| 361 | 
            +
                  return
         | 
| 362 | 
            +
                end
         | 
| 323 363 | 
             
                return @loaded_relations[method_name] if @loaded_relations.has_key?(method_name)
         | 
| 324 | 
            -
                if @relations.has_key?(method_name) and !@relations[method_name]
         | 
| 325 | 
            -
             | 
| 326 | 
            -
                 | 
| 327 | 
            -
             | 
| 328 | 
            -
                   | 
| 329 | 
            -
             | 
| 330 | 
            -
             | 
| 331 | 
            -
                   | 
| 332 | 
            -
                     | 
| 333 | 
            -
             | 
| 334 | 
            -
                      model =  | 
| 335 | 
            -
                       | 
| 336 | 
            -
                      return  | 
| 364 | 
            +
                return false if @relations.has_key?(method_name) and !@relations[method_name]
         | 
| 365 | 
            +
             | 
| 366 | 
            +
                result = relationnal_result(method_name, *arguments)
         | 
| 367 | 
            +
                if result
         | 
| 368 | 
            +
                  @loaded_relations[method_name] = result
         | 
| 369 | 
            +
                  return result
         | 
| 370 | 
            +
                elsif !self.class.many2one_relations.empty? #maybe the relation is inherited or could be inferred from a related field
         | 
| 371 | 
            +
                  self.class.many2one_relations.each do |k, field|
         | 
| 372 | 
            +
                    if @relations[k]
         | 
| 373 | 
            +
                      @loaded_relations[k] ||= self.class.load_relation(field.relation, @relations[k][0], self.class.scope_prefix, *arguments)
         | 
| 374 | 
            +
                      model = @loaded_relations[k]
         | 
| 375 | 
            +
                      model.loaded_relations[method_name] ||= model.relationnal_result(method_name, *arguments)
         | 
| 376 | 
            +
                      return model.loaded_relations[method_name] if model.loaded_relations[method_name]
         | 
| 337 377 | 
             
                    end
         | 
| 338 | 
            -
                    super
         | 
| 339 378 | 
             
                  end
         | 
| 379 | 
            +
                  super
         | 
| 340 380 | 
             
                end
         | 
| 381 | 
            +
             | 
| 382 | 
            +
              rescue
         | 
| 383 | 
            +
                display_available_fields
         | 
| 384 | 
            +
             | 
| 341 385 | 
             
                super
         | 
| 342 386 | 
             
              end
         | 
| 343 387 |  | 
| @@ -10,7 +10,7 @@ end | |
| 10 10 | 
             
            class OpenObjectWizard < OpenObjectLayoutedFields
         | 
| 11 11 | 
             
              attr_accessor :name, :id, :datas, :arch, :fields, :type, :state, :open_object_resources
         | 
| 12 12 |  | 
| 13 | 
            -
              def initialize(name, id, data, open_object_resources)
         | 
| 13 | 
            +
              def initialize(name, id, data, open_object_resources, wizard_context)
         | 
| 14 14 | 
             
                super(data['arch'], data['fields'])
         | 
| 15 15 | 
             
                @name = name
         | 
| 16 16 | 
             
                @id = id
         | 
| @@ -18,16 +18,17 @@ class OpenObjectWizard < OpenObjectLayoutedFields | |
| 18 18 | 
             
                @datas = data['datas'].symbolize_keys!
         | 
| 19 19 | 
             
                @type = data['type']
         | 
| 20 20 | 
             
                @state = data['state']
         | 
| 21 | 
            +
                @wizard_context = wizard_context
         | 
| 21 22 | 
             
              end
         | 
| 22 23 |  | 
| 23 24 | 
             
              def method_missing(method_symbol, *arguments)
         | 
| 24 25 | 
             
                values = @datas.merge((arguments[0] || {}).symbolize_keys!)
         | 
| 25 | 
            -
                context =  | 
| 26 | 
            +
                context = @wizard_context.merge(arguments[1] || {})
         | 
| 26 27 | 
             
                if @open_object_resources.size == 1
         | 
| 27 28 | 
             
                  open_object_resource = @open_object_resources[0]
         | 
| 28 29 | 
             
                  data = open_object_resource.class.old_wizard_step(@name, [open_object_resource.id], method_symbol, @id, values, context)
         | 
| 29 30 | 
             
                  if data[1]['state'] == 'end'
         | 
| 30 | 
            -
                    return open_object_resource. | 
| 31 | 
            +
                    return open_object_resource.reload_from_record!(open_object_resource.class.find(open_object_resource.id, :context => context))
         | 
| 31 32 | 
             
                  end
         | 
| 32 33 | 
             
                  @arch = data[1]['arch']
         | 
| 33 34 | 
             
                  @fields = data[1]['fields']
         | 
| @@ -0,0 +1,180 @@ | |
| 1 | 
            +
            require 'set'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module UML
         | 
| 4 | 
            +
              #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)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def self.included(base) base.extend(ClassMethods) end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def print_uml(*options)
         | 
| 9 | 
            +
                UML.print_uml(@config[:models] && @all_loaded_models.select {|model| @config[:models].index(model.openerp_model)} || @all_loaded_models, options)
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              module ClassMethods
         | 
| 13 | 
            +
                def print_uml(*options)
         | 
| 14 | 
            +
                  UML.print_uml([self], options) if self.is_a?(OpenObjectResource)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def self.display_fields(clazz)
         | 
| 19 | 
            +
                s = ""
         | 
| 20 | 
            +
                clazz.reload_fields_definition if clazz.fields.empty?
         | 
| 21 | 
            +
                clazz.fields.sort {|a,b| a[1].ttype <=> b[1].ttype}.each {|i| s << "+ #{i[1].ttype} : #{i[0]}\\l\\n"}
         | 
| 22 | 
            +
                s
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def self.print_uml(classes, *options)
         | 
| 26 | 
            +
                options = options[0] if options[0].is_a?(Array)
         | 
| 27 | 
            +
                local = (options.index(:all) == nil)
         | 
| 28 | 
            +
                detailed = (options.index(:detailed) != nil) || local && (options.index(:nodetail) == nil)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                enabled_targets = classes[0].ooor.config[:models] #defines the scope of the UML for option local
         | 
| 31 | 
            +
                m2o_edges = {}
         | 
| 32 | 
            +
                o2m_edges = {}
         | 
| 33 | 
            +
                m2m_edges = {}
         | 
| 34 | 
            +
                #instead of diplaying several relations of the same kind between two nodes which would bloat the graph,
         | 
| 35 | 
            +
                #we track them all and factor them on a common multiline edge label:
         | 
| 36 | 
            +
                connex_classes = UML.collect_edges(false, local, classes, enabled_targets, m2o_edges, o2m_edges, m2m_edges)
         | 
| 37 | 
            +
                #back links from connex classes:
         | 
| 38 | 
            +
                connex_classes += UML.collect_edges(true, local, connex_classes - classes, classes, m2o_edges, o2m_edges, m2m_edges)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                File.open('uml.dot', 'w') do |f|
         | 
| 41 | 
            +
                  f << <<-eos
         | 
| 42 | 
            +
                  digraph G {
         | 
| 43 | 
            +
                      fontname = "Bitstream Vera Sans"
         | 
| 44 | 
            +
                      fontsize = 8
         | 
| 45 | 
            +
                      label = "*** generated by OOOR by www.akretion.com ***"
         | 
| 46 | 
            +
                      node [
         | 
| 47 | 
            +
                              fontname = "Bitstream Vera Sans"
         | 
| 48 | 
            +
                              fontsize = 16
         | 
| 49 | 
            +
                              shape = "record"
         | 
| 50 | 
            +
                              fillcolor=orange
         | 
| 51 | 
            +
                              style="rounded,filled"
         | 
| 52 | 
            +
                      ]
         | 
| 53 | 
            +
                      edge [
         | 
| 54 | 
            +
                              arrowhead = "none"
         | 
| 55 | 
            +
                              fontname = "Bitstream Vera Sans"
         | 
| 56 | 
            +
                              fontsize = 9
         | 
| 57 | 
            +
                      ]
         | 
| 58 | 
            +
                  eos
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  #UML nodes definitions
         | 
| 61 | 
            +
                  ((connex_classes - classes) + classes - [IrModel, IrModelFields]).each do |model|
         | 
| 62 | 
            +
                    f << " #{model} [ label = \"{#{model.name}#{detailed ? '|' + display_fields(model) : ''}}\" ]"
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  #many2one:
         | 
| 66 | 
            +
                  f << <<-eos
         | 
| 67 | 
            +
                      edge [
         | 
| 68 | 
            +
                            headlabel = "1"
         | 
| 69 | 
            +
                            taillabel = "n"
         | 
| 70 | 
            +
                      ]
         | 
| 71 | 
            +
                      eos
         | 
| 72 | 
            +
                  m2o_edges.each do |k, v|
         | 
| 73 | 
            +
                    reverse_part = v[3].size > 0 ? "\\n/#{v[3].join("\\n")}\"]\n" : "\"]\n"
         | 
| 74 | 
            +
                    f << "edge [label = \"#{v[2].join("\\n")}#{reverse_part}"
         | 
| 75 | 
            +
                    f << "#{v[0]} -> #{v[1]}\n"
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  #one2many:
         | 
| 79 | 
            +
                  f << <<-eos
         | 
| 80 | 
            +
                      edge [
         | 
| 81 | 
            +
                            headlabel = "n"
         | 
| 82 | 
            +
                            taillabel = "1"
         | 
| 83 | 
            +
                      ]
         | 
| 84 | 
            +
                      eos
         | 
| 85 | 
            +
                  o2m_edges.each do |k, v|
         | 
| 86 | 
            +
                    f << "edge [label = \"#{v[3].join("\\n")}\"]\n"
         | 
| 87 | 
            +
                    f << "#{v[0]} -> #{v[1]}\n"
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  #many2many:
         | 
| 91 | 
            +
                  f << <<-eos
         | 
| 92 | 
            +
                      edge [
         | 
| 93 | 
            +
                            headlabel = "n"
         | 
| 94 | 
            +
                            taillabel = "n"
         | 
| 95 | 
            +
                      ]
         | 
| 96 | 
            +
                      eos
         | 
| 97 | 
            +
                  m2m_edges.each do |k, v|
         | 
| 98 | 
            +
                    reverse_part = v[3].size > 0 ? "\\n/#{v[3].join("\\n")}\"]\n" : "\"]\n"
         | 
| 99 | 
            +
                    f << "edge [label = \"#{v[2].join("\\n")}}#{reverse_part}"
         | 
| 100 | 
            +
                    f << "#{v[0]} -> #{v[1]}\n"
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  f << "}"
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                begin
         | 
| 107 | 
            +
                  cmd_line1 = "rm  uml.png"
         | 
| 108 | 
            +
                  system(cmd_line1)
         | 
| 109 | 
            +
                rescue
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
                cmd_line2 = "dot -Tpng uml.dot -o uml.png"
         | 
| 112 | 
            +
                system(cmd_line2)
         | 
| 113 | 
            +
              end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
              def self.collect_edges(is_reverse, local, classes, enabled_targets, m2o_edges, o2m_edges, m2m_edges)
         | 
| 116 | 
            +
                connex_classes = Set.new
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                classes.each do |model|
         | 
| 119 | 
            +
                  model.reload_fields_definition if model.fields.empty?
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  #many2one:
         | 
| 122 | 
            +
                  model.many2one_relations.each do |k, field|
         | 
| 123 | 
            +
                    target = UML.get_target(is_reverse, local, enabled_targets, field, model)
         | 
| 124 | 
            +
                    if target
         | 
| 125 | 
            +
                      connex_classes.add(target)
         | 
| 126 | 
            +
                      if m2o_edges["#{model}-#{target}"]
         | 
| 127 | 
            +
                        m2o_edges["#{model}-#{target}"][2] += [k]
         | 
| 128 | 
            +
                      else
         | 
| 129 | 
            +
                        m2o_edges["#{model}-#{target}"] = [model, target, [k], []]
         | 
| 130 | 
            +
                      end
         | 
| 131 | 
            +
                    end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
               classes.each do |model|
         | 
| 137 | 
            +
                  #one2many:
         | 
| 138 | 
            +
                  model.one2many_relations.each do |k, field|
         | 
| 139 | 
            +
                    target = UML.get_target(is_reverse, local, enabled_targets, field, model)
         | 
| 140 | 
            +
                    if target
         | 
| 141 | 
            +
                      connex_classes.add(target)
         | 
| 142 | 
            +
                      if m2o_edges["#{target}-#{model}"]
         | 
| 143 | 
            +
                        m2o_edges["#{target}-#{model}"][3] += [k]
         | 
| 144 | 
            +
                      elsif o2m_edges["#{model}-#{target}"]
         | 
| 145 | 
            +
                        o2m_edges["#{model}-#{target}"][3] += [k]
         | 
| 146 | 
            +
                      else
         | 
| 147 | 
            +
                        o2m_edges["#{model}-#{target}"] = [model, target, [], [k]]
         | 
| 148 | 
            +
                      end
         | 
| 149 | 
            +
                    end
         | 
| 150 | 
            +
                  end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                  #many2many:
         | 
| 153 | 
            +
                  model.many2many_relations.each do |k, field|
         | 
| 154 | 
            +
                    target = UML.get_target(is_reverse, local, enabled_targets, field, model)
         | 
| 155 | 
            +
                    if target
         | 
| 156 | 
            +
                      connex_classes.add(target)
         | 
| 157 | 
            +
                      if m2m_edges["#{model}-#{target}"]
         | 
| 158 | 
            +
                        m2m_edges["#{model}-#{target}"][2] += [k]
         | 
| 159 | 
            +
                      elsif m2m_edges["#{target}-#{model}"]
         | 
| 160 | 
            +
                        m2m_edges["#{target}-#{model}"][3] += [k]
         | 
| 161 | 
            +
                      else
         | 
| 162 | 
            +
                        m2m_edges["#{model}-#{target}"] = [model, target, [k], []]
         | 
| 163 | 
            +
                      end
         | 
| 164 | 
            +
                    end
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
                connex_classes
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
              private
         | 
| 172 | 
            +
             | 
| 173 | 
            +
              def self.get_target(is_reverse, local, enabled_targets, field, model)
         | 
| 174 | 
            +
                if (is_reverse && !local) || (!enabled_targets) || enabled_targets.index(field.relation)
         | 
| 175 | 
            +
                  target_name = model.class_name_from_model_key(field.relation)
         | 
| 176 | 
            +
                  return Object.const_defined?(target_name) ? Object.const_get(target_name) : model.ooor.define_openerp_model(field.relation, nil, nil, nil, nil, model.scope_prefix)
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
                return false
         | 
| 179 | 
            +
              end
         | 
| 180 | 
            +
            end
         | 
    
        data/lib/ooor.rb
    CHANGED
    
    | @@ -1,89 +1,95 @@ | |
| 1 1 | 
             
            require 'logger'
         | 
| 2 2 | 
             
            require 'xmlrpc/client'
         | 
| 3 | 
            +
            require 'app/models/open_object_resource'
         | 
| 4 | 
            +
            require 'app/models/uml'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class Ooor
         | 
| 7 | 
            +
              include UML
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              attr_accessor :logger, :config, :all_loaded_models, :base_url, :global_context, :ir_model_class
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              #load the custom configuration
         | 
| 12 | 
            +
              def self.load_config(config_file=nil, env=nil)
         | 
| 13 | 
            +
                config_file ||= defined?(RAILS_ROOT) && "#{RAILS_ROOT}/config/ooor.yml" || 'ooor.yml'
         | 
| 14 | 
            +
                @config = YAML.load_file(config_file)[env || 'development']
         | 
| 15 | 
            +
              rescue SystemCallError
         | 
| 16 | 
            +
                @logger.error """failed to load OOOR yaml configuration file.
         | 
| 17 | 
            +
                   make sure your app has a #{config_file} file correctly set up
         | 
| 18 | 
            +
                   if not, just copy/paste the default ooor.yml file from the OOOR Gem
         | 
| 19 | 
            +
                   to #{RAILS_ROOT}/config/ooor.yml and customize it properly\n\n"""
         | 
| 20 | 
            +
                raise
         | 
| 21 | 
            +
              end
         | 
| 3 22 |  | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                 | 
| 9 | 
            -
             | 
| 10 | 
            -
                 | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
                rescue SystemCallError
         | 
| 16 | 
            -
                  Ooor.logger.error """failed to load OOOR yaml configuration file.
         | 
| 17 | 
            -
                     make sure your app has a #{config_file} file correctly set up
         | 
| 18 | 
            -
                     if not, just copy/paste the default ooor.yml file from the OOOR Gem
         | 
| 19 | 
            -
                     to #{RAILS_ROOT}/config/ooor.yml and customize it properly\n\n"""
         | 
| 20 | 
            -
                  raise
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
             | 
| 23 | 
            -
                def loaded?
         | 
| 24 | 
            -
                  Ooor.all_loaded_models.size > 0
         | 
| 23 | 
            +
              def global_login(user, password)
         | 
| 24 | 
            +
                begin
         | 
| 25 | 
            +
                @config[:username] = user
         | 
| 26 | 
            +
                @config[:password] = password
         | 
| 27 | 
            +
                client = OpenObjectResource.client(@base_url + "/common")
         | 
| 28 | 
            +
                OpenObjectResource.try_with_pretty_error_log { client.call("login", @config[:database], user, password)}
         | 
| 29 | 
            +
                rescue SocketError => error
         | 
| 30 | 
            +
                  @logger.error """login to OpenERP server failed:
         | 
| 31 | 
            +
                   #{error.inspect}
         | 
| 32 | 
            +
                   Are your sure the server is started? Are your login parameters correct? Can this server ping the OpenERP server?
         | 
| 33 | 
            +
                   login XML/RPC url was #{@config[:url].gsub(/\/$/,'') + "/common"}"""
         | 
| 25 34 | 
             
                end
         | 
| 35 | 
            +
              end
         | 
| 26 36 |  | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 37 | 
            +
              def initialize(config, env=false)
         | 
| 38 | 
            +
                @config = config.is_a?(String) ? Ooor.load_config(config, env) : config
         | 
| 39 | 
            +
                @config.symbolize_keys!
         | 
| 40 | 
            +
                @logger = ((defined?(RAILS_ENV) and RAILS_ENV != "development") ? Rails.logger : Logger.new(STDOUT))
         | 
| 41 | 
            +
                @logger.level = config[:log_level] if config[:log_level]
         | 
| 42 | 
            +
                @base_url = config[:url].gsub(/\/$/,'')
         | 
| 43 | 
            +
                @global_context = config[:global_context] || {}
         | 
| 44 | 
            +
                config[:user_id] = global_login(config[:username] || 'admin', config[:password] || 'admin')
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                @all_loaded_models = []
         | 
| 47 | 
            +
                OpenObjectResource.logger = @logger
         | 
| 48 | 
            +
                @ir_model_class = define_openerp_model("ir.model", nil, nil, nil, nil, config[:scope_prefix] || '')
         | 
| 49 | 
            +
                define_openerp_model("ir.model.fields", nil, nil, nil, nil, config[:scope_prefix] || '')
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                if config[:models] #we load only a customized subset of the OpenERP models
         | 
| 52 | 
            +
                  models = @ir_model_class.find(:all, :domain => [['model', 'in', config[:models]]])
         | 
| 53 | 
            +
                else #we load all the models
         | 
| 54 | 
            +
                  models = @ir_model_class.find(:all).reject {|model| model.model == "ir.model" || model.model == "ir.model.fields"}
         | 
| 39 55 | 
             
                end
         | 
| 56 | 
            +
                models.each {|openerp_model| define_openerp_model(openerp_model, nil, nil, nil, nil, config[:scope_prefix] || '')}
         | 
| 57 | 
            +
              end
         | 
| 40 58 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
                   | 
| 44 | 
            -
                  Ooor.logger.level = Ooor.config[:log_level] if Ooor.config[:log_level]
         | 
| 45 | 
            -
                  Ooor.base_url = Ooor.config[:url].gsub(/\/$/,'')
         | 
| 46 | 
            -
                  Ooor.global_context = Ooor.config[:global_context] || {}
         | 
| 47 | 
            -
                  Ooor.config[:user_id] = global_login(Ooor.config[:username] || 'admin', Ooor.config[:password] || 'admin')
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                  #*************** load the models
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                  Ooor.all_loaded_models = []
         | 
| 52 | 
            -
                  OpenObjectResource.logger = Ooor.logger
         | 
| 53 | 
            -
                  OpenObjectResource.define_openerp_model("ir.model", nil, nil, nil, nil, Ooor.binding)
         | 
| 54 | 
            -
                  OpenObjectResource.define_openerp_model("ir.model.fields", nil, nil, nil, nil, Ooor.binding)
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                  if Ooor.config[:models] #we load only a customized subset of the OpenERP models
         | 
| 57 | 
            -
                    models = IrModel.find(:all, :domain => [['model', 'in', Ooor.config[:models]]])
         | 
| 58 | 
            -
                  else #we load all the models
         | 
| 59 | 
            -
                    models = IrModel.find(:all)
         | 
| 60 | 
            -
                  end
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                  models.each {|openerp_model| OpenObjectResource.define_openerp_model(openerp_model, nil, nil, nil, nil, Ooor.binding)}
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                  # *************** load the models REST controllers
         | 
| 65 | 
            -
                  if defined?(ActionController)
         | 
| 66 | 
            -
                    OpenObjectsController.logger = Ooor.logger
         | 
| 67 | 
            -
                    models.each {|openerp_model| OpenObjectsController.define_openerp_controller(openerp_model.model, Ooor.binding) }
         | 
| 68 | 
            -
                  end
         | 
| 69 | 
            -
             | 
| 59 | 
            +
              def define_openerp_model(arg, url, database, user_id, pass, scope_prefix)
         | 
| 60 | 
            +
                if arg.is_a?(String) && arg != 'ir.model' && arg != 'ir.model.fields'
         | 
| 61 | 
            +
                  arg = @ir_model_class.find(:first, :domain => [['model', '=', arg]])
         | 
| 70 62 | 
             
                end
         | 
| 71 | 
            -
             | 
| 63 | 
            +
                param = (arg.is_a? OpenObjectResource) ? arg.attributes.merge(arg.relations) : {'model' => arg}
         | 
| 64 | 
            +
                klass = Class.new(OpenObjectResource)
         | 
| 65 | 
            +
                klass.ooor = self
         | 
| 66 | 
            +
                klass.site = url || @base_url
         | 
| 67 | 
            +
                klass.user = user_id
         | 
| 68 | 
            +
                klass.password = pass
         | 
| 69 | 
            +
                klass.openerp_database = database
         | 
| 70 | 
            +
                klass.openerp_model = param['model']
         | 
| 71 | 
            +
                klass.openerp_id = url || param['id']
         | 
| 72 | 
            +
                klass.info = (param['info'] || '').gsub("'",' ')
         | 
| 73 | 
            +
                klass.name = param['name']
         | 
| 74 | 
            +
                klass.state = param['state']
         | 
| 75 | 
            +
                klass.field_ids = param['field_id']
         | 
| 76 | 
            +
                klass.access_ids = param['access_ids']
         | 
| 77 | 
            +
                klass.many2one_relations = {}
         | 
| 78 | 
            +
                klass.one2many_relations = {}
         | 
| 79 | 
            +
                klass.many2many_relations = {}
         | 
| 80 | 
            +
                klass.fields = {}
         | 
| 81 | 
            +
                klass.scope_prefix = scope_prefix
         | 
| 82 | 
            +
                model_class_name = klass.class_name_from_model_key
         | 
| 83 | 
            +
                @logger.info "registering #{model_class_name} as a Rails ActiveResource Model wrapper for OpenObject #{param['model']} model"
         | 
| 84 | 
            +
                Object.const_set(model_class_name, klass)
         | 
| 85 | 
            +
                @all_loaded_models.push(klass)
         | 
| 86 | 
            +
                klass
         | 
| 72 87 | 
             
              end
         | 
| 73 88 |  | 
| 74 89 | 
             
            end
         | 
| 75 90 |  | 
| 76 | 
            -
             | 
| 77 | 
            -
            Ooor.logger = ((defined?(RAILS_ENV) and RAILS_ENV != "development") ? Rails.logger : Logger.new(STDOUT))
         | 
| 78 | 
            -
            Ooor.binding = lambda {}
         | 
| 79 | 
            -
             | 
| 80 | 
            -
            require 'app/models/open_object_resource'
         | 
| 81 | 
            -
            require 'app/controllers/open_objects_controller'
         | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 91 | 
            +
            #Optionnal Rails settings:
         | 
| 84 92 | 
             
            if defined?(Rails)
         | 
| 85 | 
            -
               | 
| 86 | 
            -
               | 
| 87 | 
            -
                Ooor.reload!(false, false, true)
         | 
| 88 | 
            -
              end
         | 
| 93 | 
            +
              config = Ooor.load_config(false, RAILS_ENV)
         | 
| 94 | 
            +
              OOOR = Ooor.new(config) if config['bootstrap']
         | 
| 89 95 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: ooor
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
              - Raphael Valyi - www.akretion.com
         | 
| @@ -9,7 +9,7 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date:  | 
| 12 | 
            +
            date: 2010-01-18 00:00:00 -02:00
         | 
| 13 13 | 
             
            default_executable: 
         | 
| 14 14 | 
             
            dependencies: 
         | 
| 15 15 | 
             
              - !ruby/object:Gem::Dependency 
         | 
| @@ -36,7 +36,7 @@ files: | |
| 36 36 | 
             
              - lib/ooor.rb
         | 
| 37 37 | 
             
              - lib/app/models/open_object_resource.rb
         | 
| 38 38 | 
             
              - lib/app/models/open_object_ui.rb
         | 
| 39 | 
            -
              - lib/app/ | 
| 39 | 
            +
              - lib/app/models/uml.rb
         | 
| 40 40 | 
             
              - ooor.yml
         | 
| 41 41 | 
             
            has_rdoc: true
         | 
| 42 42 | 
             
            homepage: http://github.com/rvalyi/ooor
         | 
| @@ -1,139 +0,0 @@ | |
| 1 | 
            -
            require 'action_controller'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            class OpenObjectsController < ActionController::Base
         | 
| 4 | 
            -
             | 
| 5 | 
            -
              #TODO get lang from URL in before filter
         | 
| 6 | 
            -
              #TODO use timezone from HTTP header and put is in context
         | 
| 7 | 
            -
             | 
| 8 | 
            -
              # ******************** class methods ********************
         | 
| 9 | 
            -
              class << self
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                cattr_accessor :logger
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                def model_class
         | 
| 14 | 
            -
                    if defined?(@model_class)
         | 
| 15 | 
            -
                      @model_class
         | 
| 16 | 
            -
                    elsif superclass != Object && superclass.model_class
         | 
| 17 | 
            -
                      superclass.model_class.dup.freeze
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                def model_class=(_model_class)
         | 
| 22 | 
            -
                  @model_class = _model_class
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                def ids_from_param(param)
         | 
| 26 | 
            -
                  if param.split(',').size > 0
         | 
| 27 | 
            -
                    return eval param
         | 
| 28 | 
            -
                  else
         | 
| 29 | 
            -
                    return param
         | 
| 30 | 
            -
                  end
         | 
| 31 | 
            -
                end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                def define_openerp_controller(model_key, binding)
         | 
| 34 | 
            -
                  model_class_name = OpenObjectResource.class_name_from_model_key(model_key)
         | 
| 35 | 
            -
                  controller_class_name = model_class_name + "Controller"
         | 
| 36 | 
            -
                  logger.info "registering #{controller_class_name} as a Rails ActiveResource Controller wrapper for OpenObject #{model_key} model"
         | 
| 37 | 
            -
                  eval "
         | 
| 38 | 
            -
                  class #{controller_class_name} < OpenObjectsController
         | 
| 39 | 
            -
                    self.model_class = #{model_class_name}
         | 
| 40 | 
            -
                  end
         | 
| 41 | 
            -
                  ", binding
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                def load_all_controllers(map)
         | 
| 45 | 
            -
                  Ooor.all_loaded_models.each do |model|
         | 
| 46 | 
            -
                    map.resources model.gsub('.', '_').to_sym
         | 
| 47 | 
            -
                  end
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
              end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
              # ******************** instance methods ********************
         | 
| 54 | 
            -
             | 
| 55 | 
            -
              # GET /models
         | 
| 56 | 
            -
              # GET /models.xml
         | 
| 57 | 
            -
              def index
         | 
| 58 | 
            -
                @models = self.class.model_class.find(:all)
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                respond_to do |format|
         | 
| 61 | 
            -
                  format.html # index.html.erb
         | 
| 62 | 
            -
                  format.xml  { render :xml => @models }
         | 
| 63 | 
            -
                end
         | 
| 64 | 
            -
              end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
              # GET /models/1
         | 
| 67 | 
            -
              # GET /models/1.xml
         | 
| 68 | 
            -
              def show
         | 
| 69 | 
            -
                @models = self.class.model_class.find(self.class.ids_from_param(params[:id]))
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                respond_to do |format|
         | 
| 72 | 
            -
                  format.html # show.html.erb
         | 
| 73 | 
            -
                  format.xml  { render :xml => @models }
         | 
| 74 | 
            -
                  format.json  { render :json => @models }
         | 
| 75 | 
            -
                end
         | 
| 76 | 
            -
              end
         | 
| 77 | 
            -
             | 
| 78 | 
            -
              # GET /models/new
         | 
| 79 | 
            -
              # GET /models/new.xml
         | 
| 80 | 
            -
              def new
         | 
| 81 | 
            -
                @models = self.class.model_class.new
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                respond_to do |format|
         | 
| 84 | 
            -
                  format.html # new.html.erb
         | 
| 85 | 
            -
                  format.xml  { render :xml => @models }
         | 
| 86 | 
            -
                end
         | 
| 87 | 
            -
              end
         | 
| 88 | 
            -
             | 
| 89 | 
            -
              # GET /models/1/edit
         | 
| 90 | 
            -
              def edit
         | 
| 91 | 
            -
                @models = self.class.model_class.find(params[:id])
         | 
| 92 | 
            -
              end
         | 
| 93 | 
            -
             | 
| 94 | 
            -
              # POST /models
         | 
| 95 | 
            -
              # POST /models.xml
         | 
| 96 | 
            -
              def create
         | 
| 97 | 
            -
                @models = self.class.model_class.new(params[:partners])
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                respond_to do |format|
         | 
| 100 | 
            -
                  if @models.save
         | 
| 101 | 
            -
                    flash[:notice] = 'Model was successfully created.'
         | 
| 102 | 
            -
                    format.html { redirect_to(@models) }
         | 
| 103 | 
            -
                    format.xml  { render :xml => @models, :status => :created, :location => @models }
         | 
| 104 | 
            -
                  else
         | 
| 105 | 
            -
                    format.html { render :action => "new" }
         | 
| 106 | 
            -
                    format.xml  { render :xml => @models.errors, :status => :unprocessable_entity }
         | 
| 107 | 
            -
                  end
         | 
| 108 | 
            -
                end
         | 
| 109 | 
            -
              end
         | 
| 110 | 
            -
             | 
| 111 | 
            -
              # PUT /models/1
         | 
| 112 | 
            -
              # PUT /models/1.xml
         | 
| 113 | 
            -
              def update
         | 
| 114 | 
            -
                @models = self.class.model_class.find(params[:id])
         | 
| 115 | 
            -
             | 
| 116 | 
            -
                respond_to do |format|
         | 
| 117 | 
            -
                  if @models.update_attributes(params[:partners])
         | 
| 118 | 
            -
                    flash[:notice] = 'Partners was successfully updated.'
         | 
| 119 | 
            -
                    format.html { redirect_to(@models) }
         | 
| 120 | 
            -
                    format.xml  { head :ok }
         | 
| 121 | 
            -
                  else
         | 
| 122 | 
            -
                    format.html { render :action => "edit" }
         | 
| 123 | 
            -
                    format.xml  { render :xml => @models.errors, :status => :unprocessable_entity }
         | 
| 124 | 
            -
                  end
         | 
| 125 | 
            -
                end
         | 
| 126 | 
            -
              end
         | 
| 127 | 
            -
             | 
| 128 | 
            -
              # DELETE /models/1
         | 
| 129 | 
            -
              # DELETE /models/1.xml
         | 
| 130 | 
            -
              def destroy
         | 
| 131 | 
            -
                @models = self.class.model_class.find(params[:id])
         | 
| 132 | 
            -
                @models.destroy
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                respond_to do |format|
         | 
| 135 | 
            -
                  format.html { redirect_to(url_for(:action => index)) }
         | 
| 136 | 
            -
                  format.xml  { head :ok }
         | 
| 137 | 
            -
                end
         | 
| 138 | 
            -
              end
         | 
| 139 | 
            -
            end
         |