ooor 1.9.2 → 2.0.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 +23 -71
- data/Rakefile +5 -0
- data/bin/ooor +1 -0
- data/lib/ooor.rb +87 -129
- data/lib/ooor/associations.rb +64 -0
- data/lib/ooor/base.rb +218 -0
- data/lib/{app/models → ooor}/base64.rb +0 -0
- data/lib/ooor/connection.rb +37 -0
- data/lib/ooor/errors.rb +120 -0
- data/lib/ooor/field_methods.rb +153 -0
- data/lib/{app → ooor}/helpers/core_helpers.rb +2 -2
- data/lib/ooor/locale.rb +13 -0
- data/lib/ooor/mini_active_resource.rb +94 -0
- data/lib/ooor/model_registry.rb +19 -0
- data/lib/ooor/naming.rb +73 -0
- data/lib/ooor/rack.rb +114 -0
- data/lib/ooor/railtie.rb +41 -0
- data/lib/ooor/reflection.rb +537 -0
- data/lib/ooor/reflection_ooor.rb +92 -0
- data/lib/{app/models → ooor}/relation.rb +61 -22
- data/lib/ooor/relation/finder_methods.rb +113 -0
- data/lib/ooor/report.rb +53 -0
- data/lib/{app/models → ooor}/serialization.rb +18 -6
- data/lib/ooor/services.rb +133 -0
- data/lib/ooor/session.rb +120 -0
- data/lib/ooor/session_handler.rb +63 -0
- data/lib/ooor/transport.rb +34 -0
- data/lib/ooor/transport/json_client.rb +53 -0
- data/lib/ooor/transport/xml_rpc_client.rb +15 -0
- data/lib/ooor/type_casting.rb +193 -0
- data/lib/ooor/version.rb +8 -0
- data/spec/helpers/test_helper.rb +11 -0
- data/spec/install_nightly.sh +17 -0
- data/spec/ooor_spec.rb +197 -79
- data/spec/requirements.txt +19 -0
- metadata +58 -20
- data/lib/app/models/client_xmlrpc.rb +0 -34
- data/lib/app/models/open_object_resource.rb +0 -486
- data/lib/app/models/services.rb +0 -47
- data/lib/app/models/type_casting.rb +0 -134
- data/lib/app/models/uml.rb +0 -210
- data/lib/app/ui/action_window.rb +0 -96
- data/lib/app/ui/client_base.rb +0 -36
- data/lib/app/ui/form_model.rb +0 -88
- data/ooor.yml +0 -27
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:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,7 +12,7 @@ cert_chain: []
|
|
12
12
|
date: 2013-05-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: activemodel
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
@@ -27,34 +27,68 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 2.3.5
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: faraday
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
30
46
|
description: OOOR exposes OpenERP business object proxies to your Ruby (Rails or not)
|
31
47
|
application. It extends the standard ActiveResource API. Running on JRuby, OOOR
|
32
48
|
also offers a convenient bridge between OpenERP and the Java eco-system
|
33
|
-
email:
|
49
|
+
email: raphael.valyi@akretion.com
|
34
50
|
executables:
|
35
51
|
- ooor
|
36
52
|
extensions: []
|
37
53
|
extra_rdoc_files: []
|
38
54
|
files:
|
39
|
-
- README.md
|
40
|
-
- MIT-LICENSE
|
41
55
|
- lib/ooor.rb
|
42
|
-
- ooor.
|
43
|
-
- lib/
|
44
|
-
- lib/
|
45
|
-
- lib/
|
46
|
-
- lib/
|
47
|
-
- lib/
|
48
|
-
- lib/
|
49
|
-
- lib/
|
50
|
-
- lib/
|
51
|
-
- lib/
|
52
|
-
- lib/
|
53
|
-
- lib/
|
54
|
-
- lib/
|
56
|
+
- lib/ooor/naming.rb
|
57
|
+
- lib/ooor/session.rb
|
58
|
+
- lib/ooor/model_registry.rb
|
59
|
+
- lib/ooor/relation.rb
|
60
|
+
- lib/ooor/relation/finder_methods.rb
|
61
|
+
- lib/ooor/reflection_ooor.rb
|
62
|
+
- lib/ooor/connection.rb
|
63
|
+
- lib/ooor/report.rb
|
64
|
+
- lib/ooor/errors.rb
|
65
|
+
- lib/ooor/transport.rb
|
66
|
+
- lib/ooor/associations.rb
|
67
|
+
- lib/ooor/field_methods.rb
|
68
|
+
- lib/ooor/serialization.rb
|
69
|
+
- lib/ooor/base64.rb
|
70
|
+
- lib/ooor/locale.rb
|
71
|
+
- lib/ooor/version.rb
|
72
|
+
- lib/ooor/reflection.rb
|
73
|
+
- lib/ooor/helpers/core_helpers.rb
|
74
|
+
- lib/ooor/railtie.rb
|
75
|
+
- lib/ooor/rack.rb
|
76
|
+
- lib/ooor/mini_active_resource.rb
|
77
|
+
- lib/ooor/type_casting.rb
|
78
|
+
- lib/ooor/services.rb
|
79
|
+
- lib/ooor/session_handler.rb
|
80
|
+
- lib/ooor/transport/json_client.rb
|
81
|
+
- lib/ooor/transport/xml_rpc_client.rb
|
82
|
+
- lib/ooor/base.rb
|
83
|
+
- MIT-LICENSE
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- spec/requirements.txt
|
87
|
+
- spec/helpers/test_helper.rb
|
88
|
+
- spec/install_nightly.sh
|
55
89
|
- spec/ooor_spec.rb
|
56
90
|
- bin/ooor
|
57
|
-
homepage: http://github.com/
|
91
|
+
homepage: http://github.com/akretion/ooor
|
58
92
|
licenses: []
|
59
93
|
post_install_message:
|
60
94
|
rdoc_options: []
|
@@ -78,4 +112,8 @@ rubygems_version: 1.8.24
|
|
78
112
|
signing_key:
|
79
113
|
specification_version: 3
|
80
114
|
summary: OOOR - OpenObject On Ruby
|
81
|
-
test_files:
|
115
|
+
test_files:
|
116
|
+
- spec/requirements.txt
|
117
|
+
- spec/helpers/test_helper.rb
|
118
|
+
- spec/install_nightly.sh
|
119
|
+
- spec/ooor_spec.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# OOOR: OpenObject On Ruby
|
2
|
-
# Copyright (C) 2009-2012 Akretion LTDA (<http://www.akretion.com>).
|
3
|
-
# Author: Raphaël Valyi
|
4
|
-
# Licensed under the MIT license, see MIT-LICENSE file
|
5
|
-
|
6
|
-
require 'xmlrpc/client'
|
7
|
-
|
8
|
-
module Ooor
|
9
|
-
class XMLClient < XMLRPC::Client
|
10
|
-
def self.new2(ooor, url, p, timeout)
|
11
|
-
@ooor = ooor
|
12
|
-
super(url, p, timeout)
|
13
|
-
end
|
14
|
-
|
15
|
-
def call2(method, *args)
|
16
|
-
request = create().methodCall(method, *args)
|
17
|
-
data = (["<?xml version='1.0' encoding='UTF-8'?>\n"] + do_rpc(request, false).lines.to_a[1..-1]).join #encoding is not defined by OpenERP and can lead to bug with Ruby 1.9
|
18
|
-
parser().parseMethodResponse(data)
|
19
|
-
rescue RuntimeError => e
|
20
|
-
begin
|
21
|
-
#extracts the eventual error log from OpenERP response as OpenERP doesn't enforce carefully*
|
22
|
-
#the XML/RPC spec, see https://bugs.launchpad.net/openerp/+bug/257581
|
23
|
-
openerp_error_hash = eval("#{ e }".gsub("wrong fault-structure: ", ""))
|
24
|
-
rescue SyntaxError
|
25
|
-
raise e
|
26
|
-
end
|
27
|
-
if openerp_error_hash.is_a? Hash
|
28
|
-
raise RuntimeError.new "\n\n*********** OpenERP Server ERROR ***********\n#{openerp_error_hash["faultCode"]}\n#{openerp_error_hash["faultString"]}********************************************\n."
|
29
|
-
else
|
30
|
-
raise e
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,486 +0,0 @@
|
|
1
|
-
# OOOR: OpenObject On Ruby
|
2
|
-
# Copyright (C) 2009-2012 Akretion LTDA (<http://www.akretion.com>).
|
3
|
-
# Author: Raphaël Valyi
|
4
|
-
# Licensed under the MIT license, see MIT-LICENSE file
|
5
|
-
|
6
|
-
require 'rubygems'
|
7
|
-
require 'active_resource'
|
8
|
-
require 'app/ui/form_model'
|
9
|
-
require 'app/models/uml'
|
10
|
-
require 'app/models/type_casting'
|
11
|
-
require 'app/models/relation'
|
12
|
-
require 'app/models/serialization'
|
13
|
-
|
14
|
-
autoload :UML, 'app/models/uml'
|
15
|
-
|
16
|
-
module Ooor
|
17
|
-
class OpenObjectResource < ActiveResource::Base
|
18
|
-
#PREDEFINED_INHERITS = {'product.product' => 'product_tmpl_id'}
|
19
|
-
#include ActiveModel::Validations
|
20
|
-
include TypeCasting
|
21
|
-
include Serialization
|
22
|
-
|
23
|
-
# ******************** class methods ********************
|
24
|
-
class << self
|
25
|
-
|
26
|
-
cattr_accessor :logger
|
27
|
-
attr_accessor :openerp_id, :info, :access_ids, :name, :description, :openerp_model, :field_ids, :state, #class attributes associated to the OpenERP ir.model
|
28
|
-
:fields, :fields_defined, :many2one_associations, :one2many_associations, :many2many_associations, :polymorphic_m2o_associations, :associations_keys,
|
29
|
-
:database, :user_id, :scope_prefix, :ooor, :association
|
30
|
-
|
31
|
-
def model_name
|
32
|
-
@_model_name ||= begin
|
33
|
-
namespace = self.parents.detect do |n|
|
34
|
-
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
|
35
|
-
end
|
36
|
-
ActiveModel::Name.new(self, namespace, description)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def print_uml(options={})
|
41
|
-
UML.print_uml([self], options)
|
42
|
-
end
|
43
|
-
|
44
|
-
def class_name_from_model_key(model_key=self.openerp_model)
|
45
|
-
model_key.split('.').collect {|name_part| name_part.capitalize}.join
|
46
|
-
end
|
47
|
-
|
48
|
-
#similar to Object#const_get but for OpenERP model key
|
49
|
-
def const_get(model_key, context={})
|
50
|
-
klass_name = class_name_from_model_key(model_key)
|
51
|
-
klass = (self.scope_prefix ? Object.const_get(self.scope_prefix) : Object).const_defined?(klass_name) ? (self.scope_prefix ? Object.const_get(self.scope_prefix) : Object).const_get(klass_name) : @ooor.define_openerp_model({'model' => model_key}, self.scope_prefix)
|
52
|
-
klass.reload_fields_definition(false, context)
|
53
|
-
klass
|
54
|
-
end
|
55
|
-
|
56
|
-
def create(attributes = {}, context={}, default_get_list=false, reload=true)
|
57
|
-
self.new(attributes, default_get_list, context).tap { |resource| resource.save(context, reload) }
|
58
|
-
end
|
59
|
-
|
60
|
-
def reload_fields_definition(force=false, context={})
|
61
|
-
if force or not @fields_defined
|
62
|
-
@fields_defined = true
|
63
|
-
@fields = {}
|
64
|
-
rpc_execute("fields_get").each do |k, field|
|
65
|
-
case field['type']
|
66
|
-
when 'many2one'
|
67
|
-
@many2one_associations[k] = field
|
68
|
-
when 'one2many'
|
69
|
-
@one2many_associations[k] = field
|
70
|
-
when 'many2many'
|
71
|
-
@many2many_associations[k] = field
|
72
|
-
when 'reference'
|
73
|
-
@polymorphic_m2o_associations[k] = field
|
74
|
-
else
|
75
|
-
# if ['integer', 'int8'].index(field['type'])
|
76
|
-
# self.send :validates_numericality_of, k, :only_integer => true
|
77
|
-
# elsif field['type'] == 'float'
|
78
|
-
# self.send :validates_numericality_of, k
|
79
|
-
# elsif field['type'] == 'char'
|
80
|
-
# self.send :validates_length_of, k, :maximum => field['size'] || 128
|
81
|
-
# end
|
82
|
-
@fields[k] = field if field['name'] != 'id'
|
83
|
-
end
|
84
|
-
# if field["required"]
|
85
|
-
# if field['type'] == 'many2one'
|
86
|
-
# next if PREDEFINED_INHERITS[self.openerp_model] == k
|
87
|
-
# end
|
88
|
-
# self.send :validates_presence_of, k
|
89
|
-
# end
|
90
|
-
end
|
91
|
-
@associations_keys = @many2one_associations.keys + @one2many_associations.keys + @many2many_associations.keys + @polymorphic_m2o_associations.keys
|
92
|
-
(@fields.keys + @associations_keys).each do |meth| #generates method handlers for auto-completion tools such as jirb_swing
|
93
|
-
unless self.respond_to?(meth)
|
94
|
-
self.instance_eval do
|
95
|
-
define_method meth do |*args|
|
96
|
-
self.send :method_missing, *[meth, *args]
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
logger.debug "#{fields.size} fields loaded in model #{self.name}"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# ******************** remote communication ********************
|
106
|
-
|
107
|
-
#OpenERP search method
|
108
|
-
def search(domain=[], offset=0, limit=false, order=false, context={}, count=false)
|
109
|
-
rpc_execute('search', to_openerp_domain(domain), offset, limit, order, context, count)
|
110
|
-
end
|
111
|
-
|
112
|
-
def relation; @relation ||= Relation.new(self); end
|
113
|
-
def where(opts, *rest); relation.where(opts, *rest); end
|
114
|
-
def all(*args); relation.all(*args); end
|
115
|
-
def limit(value); relation.limit(value); end
|
116
|
-
def order(value); relation.order(value); end
|
117
|
-
def offset(value); relation.offset(value); end
|
118
|
-
|
119
|
-
#corresponding method for OpenERP osv.execute(self, db, uid, obj, method, *args, **kw) method
|
120
|
-
def rpc_execute(method, *args)
|
121
|
-
rpc_execute_with_object(@openerp_model, method, *args)
|
122
|
-
end
|
123
|
-
|
124
|
-
def rpc_execute_with_object(object, method, *args)
|
125
|
-
if args[-1].is_a? Hash #context
|
126
|
-
user_id = args[-1].delete(:user_id) || args[-1].delete('user_id') || @user_id || @ooor.config[:user_id]
|
127
|
-
password = args[-1].delete(:password) || args[-1].delete('password') || @password || @ooor.config[:password]
|
128
|
-
database = args[-1].delete(:database) || args[-1].delete('database') || @database || @ooor.config[:database]
|
129
|
-
args[-1].delete(:context)
|
130
|
-
else
|
131
|
-
user_id = @user_id || @ooor.config[:user_id] #TODO @user_id useless?
|
132
|
-
password = @password || @ooor.config[:password]
|
133
|
-
database = @database || @ooor.config[:database]
|
134
|
-
end
|
135
|
-
rpc_execute_with_all(database, user_id, password, object, method, *args)
|
136
|
-
end
|
137
|
-
|
138
|
-
#corresponding method for OpenERP osv.execute(self, db, uid, obj, method, *args, **kw) method
|
139
|
-
def rpc_execute_with_all(db, uid, pass, obj, method, *args)
|
140
|
-
clean_request_args!(args)
|
141
|
-
reload_fields_definition(false, {:user_id => uid, :password => pass})
|
142
|
-
logger.debug "OOOR RPC: rpc_method: 'execute', db: #{db}, uid: #{uid}, pass: #, obj: #{obj}, method: #{method}, *args: #{args.inspect}"
|
143
|
-
cast_answer_to_ruby!(@ooor.get_rpc_client("#{(@database && @site || @ooor.base_url)}/object").call("execute", db, uid, pass, obj, method, *args))
|
144
|
-
end
|
145
|
-
|
146
|
-
#corresponding method for OpenERP osv.exec_workflow(self, db, uid, obj, method, *args)
|
147
|
-
def rpc_exec_workflow(action, *args)
|
148
|
-
rpc_exec_workflow_with_object(@openerp_model, action, *args)
|
149
|
-
end
|
150
|
-
|
151
|
-
def rpc_exec_workflow_with_object(object, action, *args)
|
152
|
-
rpc_exec_workflow_with_all(@database || @ooor.config[:database], @user_id || @ooor.config[:user_id], @password || @ooor.config[:password], object, action, *args)
|
153
|
-
end
|
154
|
-
|
155
|
-
def rpc_exec_workflow_with_all(db, uid, pass, obj, action, *args)
|
156
|
-
clean_request_args!(args)
|
157
|
-
reload_fields_definition()
|
158
|
-
logger.debug "OOOR RPC: 'exec_workflow', db: #{db}, uid: #{uid}, pass: #, obj: #{obj}, action: #{action}, *args: #{args.inspect}"
|
159
|
-
cast_answer_to_ruby!(@ooor.get_rpc_client("#{(@database && @site || @ooor.base_url)}/object").call("exec_workflow", db, uid, pass, obj, action, *args))
|
160
|
-
end
|
161
|
-
|
162
|
-
def old_wizard_step(wizard_name, ids, step='init', wizard_id=nil, form={}, context={}, report_type='pdf')
|
163
|
-
context = @ooor.global_context.merge(context)
|
164
|
-
cast_map_to_openerp!(form)
|
165
|
-
unless wizard_id
|
166
|
-
logger.debug "OOOR RPC: 'create old_wizard_step' #{wizard_name}"
|
167
|
-
wizard_id = cast_answer_to_ruby!(@ooor.get_rpc_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))
|
168
|
-
end
|
169
|
-
params = {'model' => @openerp_model, 'form' => form, 'report_type' => report_type}
|
170
|
-
params.merge!({'id' => ids[0], 'ids' => ids}) if ids
|
171
|
-
logger.debug "OOOR RPC: 'execute old_wizard_step' #{wizard_id}, #{params.inspect}, #{step}, #{context}"
|
172
|
-
[wizard_id, cast_answer_to_ruby!(@ooor.get_rpc_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, params, step, context))]
|
173
|
-
end
|
174
|
-
|
175
|
-
def method_missing(method_symbol, *arguments)
|
176
|
-
raise RuntimeError.new("Invalid RPC method: #{method_symbol}") if [:type!, :allowed!].index(method_symbol)
|
177
|
-
self.rpc_execute(method_symbol.to_s, *arguments)
|
178
|
-
end
|
179
|
-
|
180
|
-
#Added methods to obtain report data for a model
|
181
|
-
def report(report_name, ids, report_type='pdf', context={})
|
182
|
-
context = @ooor.global_context.merge(context)
|
183
|
-
params = {'model' => @openerp_model, 'id' => ids[0], 'report_type' => report_type}
|
184
|
-
@ooor.get_rpc_client("#{(@database && @site || @ooor.base_url)}/report").call("report", @database || @ooor.config[:database], @user_id || @ooor.config[:user_id], @password || @ooor.config[:password], report_name, ids, params, context)
|
185
|
-
end
|
186
|
-
|
187
|
-
def report_get(report_id, context={})
|
188
|
-
context = @ooor.global_context.merge(context)
|
189
|
-
@ooor.get_rpc_client("#{(@database && @site || @ooor.base_url)}/report").call("report_get", @database || @ooor.config[:database], @user_id || @ooor.config[:user_id], @password || @ooor.config[:password], report_id)
|
190
|
-
end
|
191
|
-
|
192
|
-
def get_report_data(report_name, ids, report_type='pdf', context={})
|
193
|
-
report_id = self.report(report_name, ids, report_type, context)
|
194
|
-
if report_id
|
195
|
-
state = false
|
196
|
-
attempt = 0
|
197
|
-
while not state
|
198
|
-
report = self.report_get(report_id, context)
|
199
|
-
state = report["state"]
|
200
|
-
attempt = 1
|
201
|
-
if not state
|
202
|
-
sleep(0.1)
|
203
|
-
attempt += 1
|
204
|
-
else
|
205
|
-
return [report["result"],report["format"]]
|
206
|
-
end
|
207
|
-
if attempt > 100
|
208
|
-
logger.debug "OOOR RPC: 'Printing Aborted!'"
|
209
|
-
break
|
210
|
-
end
|
211
|
-
end
|
212
|
-
else
|
213
|
-
logger.debug "OOOR RPC: 'report not found'"
|
214
|
-
end
|
215
|
-
return nil
|
216
|
-
end
|
217
|
-
|
218
|
-
def find(*arguments)
|
219
|
-
scope = arguments.slice!(0)
|
220
|
-
options = arguments.slice!(0) || {}
|
221
|
-
case scope
|
222
|
-
when :all then find_every(options)
|
223
|
-
when :first then find_every(options.merge(:limit => 1)).first
|
224
|
-
when :last then find_every(options).last
|
225
|
-
when :one then find_one(options)
|
226
|
-
else find_single(scope, options)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
#******************** finders low level implementation ********************
|
231
|
-
private
|
232
|
-
|
233
|
-
def find_every(options)
|
234
|
-
domain = options[:domain] || []
|
235
|
-
context = options[:context] || {}
|
236
|
-
#prefix_options, domain = split_options(options[:params]) unless domain
|
237
|
-
ids = rpc_execute('search', to_openerp_domain(domain), options[:offset] || 0, options[:limit] || false, options[:order] || false, context.dup)
|
238
|
-
!ids.empty? && ids[0].is_a?(Integer) && find_single(ids, options) || []
|
239
|
-
end
|
240
|
-
|
241
|
-
#actually finds many resources specified with scope = ids_array
|
242
|
-
def find_single(scope, options)
|
243
|
-
context = options[:context] || {}
|
244
|
-
reload_fields_definition(false, context)
|
245
|
-
all_fields = @fields.merge(@many2one_associations).merge(@one2many_associations).merge(@many2many_associations).merge(@polymorphic_m2o_associations)
|
246
|
-
fields = options[:fields] || options[:only] || all_fields.keys.select {|k| all_fields[k]["type"] != "binary" && (options[:include_functions] || !all_fields[k]["function"])}
|
247
|
-
# prefix_options, query_options = split_options(options[:params])
|
248
|
-
is_collection = true
|
249
|
-
scope = [scope] and is_collection = false if !scope.is_a? Array
|
250
|
-
scope.map! do |item|
|
251
|
-
if item.is_a?(String) && item.to_i == 0#triggers ir_model_data absolute reference lookup
|
252
|
-
tab = item.split(".")
|
253
|
-
domain = [['name', '=', tab[-1]]]
|
254
|
-
domain += [['module', '=', tab[-2]]] if tab[-2]
|
255
|
-
ir_model_data = const_get('ir.model.data', context).find(:first, :domain => domain)
|
256
|
-
ir_model_data && ir_model_data.res_id && search([['id', '=', ir_model_data.res_id]])[0]
|
257
|
-
else
|
258
|
-
item
|
259
|
-
end
|
260
|
-
end.reject! {|item| !item}
|
261
|
-
records = rpc_execute('read', scope, fields, context.dup)
|
262
|
-
records = records.sort_by {|r| scope.index(r["id"])} #TODO use sort_by! in Ruby 1.9
|
263
|
-
active_resources = []
|
264
|
-
records.each do |record|
|
265
|
-
r = {}
|
266
|
-
record.each_pair do |k,v|
|
267
|
-
r[k.to_sym] = v
|
268
|
-
end
|
269
|
-
active_resources << new(r, [], context, true)
|
270
|
-
end
|
271
|
-
unless is_collection
|
272
|
-
return active_resources[0]
|
273
|
-
end
|
274
|
-
return active_resources
|
275
|
-
end
|
276
|
-
|
277
|
-
end
|
278
|
-
|
279
|
-
self.name = "OpenObjectResource"
|
280
|
-
|
281
|
-
|
282
|
-
# ******************** instance methods ********************
|
283
|
-
|
284
|
-
attr_accessor :associations, :loaded_associations, :ir_model_data_id, :object_session
|
285
|
-
|
286
|
-
def object_db; object_session[:database] || self.class.database || self.class.ooor.config[:database]; end
|
287
|
-
def object_uid; object_session[:user_id] || self.class.user_id || self.class.ooor.config[:user_id]; end
|
288
|
-
def object_pass; object_session[:password] || self.class.password || self.class.ooor.config[:password]; end
|
289
|
-
|
290
|
-
# Ruby 1.9.compat, See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary/
|
291
|
-
def to_ary # :nodoc:
|
292
|
-
nil
|
293
|
-
end
|
294
|
-
|
295
|
-
#try to wrap the object context inside the query.
|
296
|
-
def rpc_execute(method, *args)
|
297
|
-
if args[-1].is_a? Hash
|
298
|
-
args[-1] = self.class.ooor.global_context.merge(object_session[:context]).merge(args[-1])
|
299
|
-
elsif args.is_a?(Array)
|
300
|
-
args += [self.class.ooor.global_context.merge(object_session[:context])]
|
301
|
-
end
|
302
|
-
self.class.rpc_execute_with_all(object_db, object_uid, object_pass, self.class.openerp_model, method, *args)
|
303
|
-
end
|
304
|
-
|
305
|
-
def reload_from_record!(record) load(record.attributes.merge(record.associations)) end
|
306
|
-
|
307
|
-
def load(attributes, remove_root=false)#an attribute might actually be a association too, will be determined here
|
308
|
-
self.class.reload_fields_definition(false, object_session)
|
309
|
-
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
|
310
|
-
@prefix_options, attributes = split_options(attributes)
|
311
|
-
@associations ||= {}
|
312
|
-
@attributes ||= {}
|
313
|
-
@loaded_associations = {}
|
314
|
-
attributes.each do |key, value|
|
315
|
-
skey = key.to_s
|
316
|
-
if self.class.associations_keys.index(skey) || value.is_a?(Array) #FIXME may miss m2o with inherits!
|
317
|
-
@associations[skey] = value #the association because we want the method to load the association through method missing
|
318
|
-
else
|
319
|
-
@attributes[skey] = (value == false)? nil : value
|
320
|
-
end
|
321
|
-
end
|
322
|
-
self
|
323
|
-
end
|
324
|
-
|
325
|
-
def available_fields
|
326
|
-
msg = "\n*** AVAILABLE FIELDS ON #{self.class.name} ARE: ***"
|
327
|
-
msg << "\n\n" << self.class.fields.sort {|a,b| a[1]['type']<=>b[1]['type']}.map {|i| "#{i[1]['type']} --- #{i[0]}"}.join("\n")
|
328
|
-
%w[many2one one2many many2many polymorphic_m2o].each do |kind|
|
329
|
-
msg << "\n\n"
|
330
|
-
msg << (self.class.send "#{kind}_associations").map {|k, v| "{kind} --- #{v['relation']} --- #{k}"}.join("\n")
|
331
|
-
end
|
332
|
-
msg
|
333
|
-
end
|
334
|
-
|
335
|
-
#takes care of reading OpenERP default field values.
|
336
|
-
def initialize(attributes = {}, default_get_list=false, context={}, persisted=false)
|
337
|
-
@attributes = {}
|
338
|
-
@prefix_options = {}
|
339
|
-
@ir_model_data_id = attributes.delete(:ir_model_data_id)
|
340
|
-
@object_session = {}
|
341
|
-
@object_session[:user_id] = context.delete :user_id
|
342
|
-
@object_session[:database] = context.delete :database
|
343
|
-
@object_session[:password] = context.delete :password
|
344
|
-
@object_session[:context] = context
|
345
|
-
@persisted = persisted #TODO match 3.1 ActiveResource API
|
346
|
-
if default_get_list == []
|
347
|
-
load(attributes)
|
348
|
-
else
|
349
|
-
self.class.reload_fields_definition(false, object_session)
|
350
|
-
attributes = rpc_execute("default_get", default_get_list || self.class.fields.keys + self.class.associations_keys, object_session[:context]).symbolize_keys!.merge(attributes.symbolize_keys!)
|
351
|
-
load(attributes)
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
def save(context={}, reload=true)
|
356
|
-
new? ? create(context, reload) : update(context, reload)
|
357
|
-
end
|
358
|
-
|
359
|
-
#compatible with the Rails way but also supports OpenERP context
|
360
|
-
def create(context={}, reload=true)
|
361
|
-
self.id = rpc_execute('create', to_openerp_hash!, context)
|
362
|
-
IrModelData.create(:model => self.class.openerp_model, :module => @ir_model_data_id[0], :name=> @ir_model_data_id[1], :res_id => self.id) if @ir_model_data_id
|
363
|
-
reload_from_record!(self.class.find(self.id, :context => context)) if reload
|
364
|
-
@persisted = true
|
365
|
-
end
|
366
|
-
|
367
|
-
#compatible with the Rails way but also supports OpenERP context
|
368
|
-
def update(context={}, reload=true)
|
369
|
-
rpc_execute('write', [self.id], to_openerp_hash!, context)
|
370
|
-
reload_fields(context) if reload
|
371
|
-
@persisted = true
|
372
|
-
end
|
373
|
-
|
374
|
-
|
375
|
-
#compatible with the Rails way but also supports OpenERP context
|
376
|
-
def destroy(context={})
|
377
|
-
rpc_execute('unlink', [self.id], context)
|
378
|
-
end
|
379
|
-
|
380
|
-
#OpenERP copy method, load persisted copied Object
|
381
|
-
def copy(defaults={}, context={})
|
382
|
-
self.class.find(rpc_execute('copy', self.id, defaults, context), :context => context)
|
383
|
-
end
|
384
|
-
|
385
|
-
#Generic OpenERP rpc method call
|
386
|
-
def call(method, *args) rpc_execute(method, *args) end
|
387
|
-
|
388
|
-
#Generic OpenERP on_change method
|
389
|
-
def on_change(on_change_method, field_name, field_value, *args)
|
390
|
-
result = self.class.rpc_execute_with_all(object_db, object_uid, object_pass, self.class.openerp_model, on_change_method, self.id && [id] || [], *args) #OpenERP doesn't accept context systematically in on_change events unfortunately
|
391
|
-
if result["warning"]
|
392
|
-
self.class.logger.info result["warning"]["title"]
|
393
|
-
self.class.logger.info result["warning"]["message"]
|
394
|
-
end
|
395
|
-
load(@attributes.merge({field_name => field_value}).merge(result["value"]))
|
396
|
-
end
|
397
|
-
|
398
|
-
#wrapper for OpenERP exec_workflow Business Process Management engine
|
399
|
-
def wkf_action(action, context={}, reload=true)
|
400
|
-
self.class.rpc_exec_workflow_with_all(object_db, object_uid, object_pass, self.class.openerp_model, action, self.id) #FIXME looks like OpenERP exec_workflow doesn't accept context but it might be a bug
|
401
|
-
reload_fields(context) if reload
|
402
|
-
end
|
403
|
-
|
404
|
-
def old_wizard_step(wizard_name, step='init', wizard_id=nil, form={}, context={})
|
405
|
-
result = self.class.old_wizard_step(wizard_name, [self.id], step, wizard_id, form, {})
|
406
|
-
FormModel.new(wizard_name, result[0], nil, nil, result[1], [self], self.class.ooor.global_context)
|
407
|
-
end
|
408
|
-
|
409
|
-
def log(message, context={}) rpc_execute('log', id, message, context) end
|
410
|
-
|
411
|
-
def type() method_missing(:type) end #skips deprecated Object#type method
|
412
|
-
|
413
|
-
# fakes associations like much like ActiveRecord according to the cached OpenERP data model
|
414
|
-
def relationnal_result(method_name, *arguments)
|
415
|
-
self.class.reload_fields_definition(false, object_session)
|
416
|
-
if self.class.many2one_associations.has_key?(method_name)
|
417
|
-
return false unless @associations[method_name]
|
418
|
-
load_association(self.class.many2one_associations[method_name]['relation'], @associations[method_name].is_a?(Integer) && @associations[method_name] || @associations[method_name][0], *arguments)
|
419
|
-
elsif self.class.one2many_associations.has_key?(method_name)
|
420
|
-
load_association(self.class.one2many_associations[method_name]['relation'], @associations[method_name], *arguments) || []
|
421
|
-
elsif self.class.many2many_associations.has_key?(method_name)
|
422
|
-
load_association(self.class.many2many_associations[method_name]['relation'], @associations[method_name], *arguments) || []
|
423
|
-
elsif self.class.polymorphic_m2o_associations.has_key?(method_name)
|
424
|
-
values = @associations[method_name].split(',')
|
425
|
-
load_association(values[0], values[1].to_i, *arguments)
|
426
|
-
else
|
427
|
-
false
|
428
|
-
end
|
429
|
-
end
|
430
|
-
|
431
|
-
def method_missing(method_symbol, *arguments)
|
432
|
-
method_name = method_symbol.to_s
|
433
|
-
is_assign = method_name.end_with?('=')
|
434
|
-
method_key = method_name.sub('=', '')
|
435
|
-
self.class.reload_fields_definition(false, object_session)
|
436
|
-
|
437
|
-
if attributes.has_key?(method_key)
|
438
|
-
return super
|
439
|
-
elsif @loaded_associations.has_key?(method_name)
|
440
|
-
@loaded_associations[method_name]
|
441
|
-
elsif @associations.has_key?(method_name)
|
442
|
-
result = relationnal_result(method_name, *arguments)
|
443
|
-
@loaded_associations[method_name] = result and return result if result
|
444
|
-
elsif is_assign
|
445
|
-
known_associations = self.class.associations_keys + self.class.many2one_associations.collect {|k, field| self.class.const_get(field['relation'], object_session).associations_keys}.flatten
|
446
|
-
if known_associations.index(method_key)
|
447
|
-
@associations[method_key] = arguments[0]
|
448
|
-
@loaded_associations[method_key] = arguments[0]
|
449
|
-
return
|
450
|
-
end
|
451
|
-
know_fields = self.class.fields.keys + self.class.many2one_associations.collect {|k, field| self.class.const_get(field['relation'], object_session).fields.keys}.flatten
|
452
|
-
@attributes[method_key] = arguments[0] and return if know_fields.index(method_key)
|
453
|
-
elsif self.class.fields.has_key?(method_key) || self.class.associations_keys.index(method_name) #unloaded field/association
|
454
|
-
load(rpc_execute('read', [id], [method_key], *arguments || object_session)[0] || {})
|
455
|
-
return method_missing(method_key, *arguments)
|
456
|
-
elsif id #it's an action
|
457
|
-
arguments += [{}] unless arguments.last.is_a?(Hash)
|
458
|
-
rpc_execute(method_key, [id], *arguments) #we assume that's an action
|
459
|
-
else
|
460
|
-
super
|
461
|
-
end
|
462
|
-
|
463
|
-
rescue RuntimeError => e
|
464
|
-
e.message << "\n" + available_fields if e.message.index("AttributeError")
|
465
|
-
raise e
|
466
|
-
end
|
467
|
-
|
468
|
-
#Add get_report_data to obtain [report["result"],report["format]] of a concrete openERP Object
|
469
|
-
def get_report_data(report_name, report_type="pdf", context={})
|
470
|
-
self.class.get_report_data(report_name, [self.id], report_type, context)
|
471
|
-
end
|
472
|
-
|
473
|
-
private
|
474
|
-
|
475
|
-
def load_association(model_key, ids, *arguments)
|
476
|
-
options = arguments.extract_options!
|
477
|
-
related_class = self.class.const_get(model_key, object_session)
|
478
|
-
related_class.send :find, ids, :fields => options[:fields] || options[:only] || [], :context => options[:context] || object_session[:context]
|
479
|
-
end
|
480
|
-
|
481
|
-
def reload_fields(context)
|
482
|
-
records = self.class.find(self.id, :context => context, :fields => @attributes.keys + @associations.keys)
|
483
|
-
reload_from_record!(records)
|
484
|
-
end
|
485
|
-
end
|
486
|
-
end
|