ooor 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +1 -0
- data/bin/ooor +1 -0
- data/lib/ooor.rb +2 -0
- data/lib/ooor/associations.rb +30 -40
- data/lib/ooor/base.rb +22 -113
- data/lib/ooor/callbacks.rb +18 -0
- data/lib/ooor/field_methods.rb +133 -85
- data/lib/ooor/helpers/core_helpers.rb +9 -63
- data/lib/ooor/mini_active_resource.rb +0 -18
- data/lib/ooor/naming.rb +2 -2
- data/lib/ooor/persistence.rb +140 -0
- data/lib/ooor/railtie.rb +2 -1
- data/lib/ooor/reflection.rb +11 -399
- data/lib/ooor/reflection_ooor.rb +36 -11
- data/lib/ooor/relation.rb +48 -23
- data/lib/ooor/type_casting.rb +108 -75
- data/lib/ooor/version.rb +1 -1
- data/spec/ooor_spec.rb +133 -27
- metadata +35 -40
data/lib/ooor/reflection_ooor.rb
CHANGED
@@ -6,23 +6,29 @@ module Ooor
|
|
6
6
|
module ReflectionOoor # :nodoc:
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
|
+
def column_for_attribute(name)
|
10
|
+
self.class.columns_hash[name.to_s]
|
11
|
+
end
|
12
|
+
|
9
13
|
module ClassMethods
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def columns_hash(view_fields=nil)
|
15
|
+
if view_fields || !@t.columns_hash
|
16
|
+
view_fields ||= {}
|
17
|
+
reload_fields_definition()
|
18
|
+
@t.columns_hash ||= {}
|
19
|
+
@t.fields.each do |k, field|
|
20
|
+
unless @t.associations_keys.index(k)
|
21
|
+
@t.columns_hash[k] = field.merge({type: to_rails_type(view_fields[k] && view_fields[k]['type'] || field['type'])})
|
22
|
+
end
|
16
23
|
end
|
24
|
+
@t.columns_hash
|
25
|
+
else
|
26
|
+
@t.columns_hash
|
17
27
|
end
|
18
|
-
@t.columns_hash
|
19
|
-
end
|
20
|
-
|
21
|
-
def column_for_attribute(name)
|
22
|
-
columns_hash[name.to_s]
|
23
28
|
end
|
24
29
|
|
25
30
|
def create_reflection(name)
|
31
|
+
reload_fields_definition()
|
26
32
|
options = {}
|
27
33
|
if many2one_associations.keys.include?(name)
|
28
34
|
macro = :belongs_to
|
@@ -86,6 +92,25 @@ module Ooor
|
|
86
92
|
@klass ||= connection.class_name_from_model_key(class_name).constantize
|
87
93
|
end
|
88
94
|
|
95
|
+
def initialize(macro, name, options, active_record)
|
96
|
+
super
|
97
|
+
@collection = macro.in?([:has_many, :has_and_belongs_to_many])
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns a new, unsaved instance of the associated class. +options+ will
|
101
|
+
# be passed to the class's constructor.
|
102
|
+
def build_association(*options, &block)
|
103
|
+
klass.new(*options, &block)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns whether or not this association reflection is for a collection
|
107
|
+
# association. Returns +true+ if the +macro+ is either +has_many+ or
|
108
|
+
# +has_and_belongs_to_many+, +false+ otherwise.
|
109
|
+
def collection?
|
110
|
+
@collection
|
111
|
+
end
|
112
|
+
|
113
|
+
|
89
114
|
end
|
90
115
|
|
91
116
|
end
|
data/lib/ooor/relation.rb
CHANGED
@@ -14,6 +14,7 @@ module Ooor
|
|
14
14
|
:select_values, :group_values, :order_values, :reorder_flag, :joins_values, :where_values, :having_values,
|
15
15
|
:limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value, :from_value, :page_value, :per_value
|
16
16
|
alias :loaded? :loaded
|
17
|
+
alias :model :klass
|
17
18
|
|
18
19
|
def build_where(opts, other = [])#TODO OpenERP domain is more than just the intersection of restrictions
|
19
20
|
case opts
|
@@ -54,14 +55,14 @@ module Ooor
|
|
54
55
|
|
55
56
|
def order(*args)
|
56
57
|
relation = clone
|
57
|
-
relation.order_values += args.flatten unless args.blank?
|
58
|
+
relation.order_values += args.flatten unless args.blank? || args[0] == false
|
58
59
|
relation
|
59
60
|
end
|
60
61
|
|
61
|
-
def count(column_name = nil, options = {})
|
62
|
-
column_name, options = nil, column_name if column_name.is_a?(Hash)
|
63
|
-
calculate(:count, column_name, options)
|
64
|
-
end
|
62
|
+
# def count(column_name = nil, options = {}) #TODO possible to implement?
|
63
|
+
# column_name, options = nil, column_name if column_name.is_a?(Hash)
|
64
|
+
# calculate(:count, column_name, options)
|
65
|
+
# end
|
65
66
|
|
66
67
|
def initialize(klass, options={})
|
67
68
|
@klass = klass
|
@@ -78,6 +79,8 @@ module Ooor
|
|
78
79
|
@klass.new(*args, &block)
|
79
80
|
end
|
80
81
|
|
82
|
+
alias build new
|
83
|
+
|
81
84
|
def reload
|
82
85
|
reset
|
83
86
|
to_a # force reload
|
@@ -115,6 +118,14 @@ module Ooor
|
|
115
118
|
args.any? ? apply_finder_options(args.first).to_a : to_a
|
116
119
|
end
|
117
120
|
|
121
|
+
def first(*args)
|
122
|
+
limit(1).order('id').all(*args).first
|
123
|
+
end
|
124
|
+
|
125
|
+
def last(*args)
|
126
|
+
limit(1).order('id DESC').all(*args).first
|
127
|
+
end
|
128
|
+
|
118
129
|
def to_a
|
119
130
|
if loaded?
|
120
131
|
@records
|
@@ -128,26 +139,10 @@ module Ooor
|
|
128
139
|
if @options && @options[:name_search]
|
129
140
|
name_search = @klass.name_search(@options[:name_search], where_values, 'ilike', @options[:context], @limit_value)
|
130
141
|
@records = name_search.map do |tuple|
|
131
|
-
|
132
|
-
r.id = tuple[0]
|
133
|
-
r #TODO load the fields optionally
|
142
|
+
@klass.new({name: tuple[1]}, []).tap { |r| r.id = tuple[0] } #TODO load the fields optionally
|
134
143
|
end
|
135
144
|
else
|
136
|
-
|
137
|
-
offset = @per_value * @page_value
|
138
|
-
limit = @per_value
|
139
|
-
else
|
140
|
-
offset = @offset_value
|
141
|
-
limit = @limit_value || false
|
142
|
-
end
|
143
|
-
@loaded = true
|
144
|
-
opts = @options.merge({
|
145
|
-
domain: where_values,
|
146
|
-
offset: offset,
|
147
|
-
limit: limit,
|
148
|
-
order: search_order,
|
149
|
-
})
|
150
|
-
@records = @klass.find(:all, opts)
|
145
|
+
load_records_page(search_order)
|
151
146
|
end
|
152
147
|
end
|
153
148
|
end
|
@@ -156,8 +151,38 @@ module Ooor
|
|
156
151
|
false
|
157
152
|
end
|
158
153
|
|
154
|
+
def inspect
|
155
|
+
entries = to_a.take([limit_value, 11].compact.min).map!(&:inspect)
|
156
|
+
entries[10] = '...' if entries.size == 11
|
157
|
+
|
158
|
+
"#<#{self.class.name} [#{entries.join(', ')}]>"
|
159
|
+
end
|
160
|
+
|
159
161
|
protected
|
160
162
|
|
163
|
+
def load_records_page(search_order)
|
164
|
+
if @per_value && @page_value
|
165
|
+
offset = @per_value * @page_value
|
166
|
+
limit = @per_value
|
167
|
+
else
|
168
|
+
offset = @offset_value
|
169
|
+
limit = @limit_value || false
|
170
|
+
end
|
171
|
+
@loaded = true
|
172
|
+
opts = @options.merge({
|
173
|
+
domain: where_values,
|
174
|
+
offset: offset,
|
175
|
+
limit: limit,
|
176
|
+
order: search_order,
|
177
|
+
})
|
178
|
+
scope = @options.delete(:ids) || :all
|
179
|
+
if scope == []
|
180
|
+
@records = []
|
181
|
+
else
|
182
|
+
@records = @klass.find(scope, opts)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
161
186
|
def method_missing(method, *args, &block)
|
162
187
|
if Array.method_defined?(method)
|
163
188
|
to_a.send(method, *args, &block)
|
data/lib/ooor/type_casting.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# OOOR: OpenObject On Ruby
|
2
|
-
# Copyright (C) 2009-
|
2
|
+
# Copyright (C) 2009-2014 Akretion LTDA (<http://www.akretion.com>).
|
3
3
|
# Author: Raphaël Valyi
|
4
4
|
# Licensed under the MIT license, see MIT-LICENSE file
|
5
5
|
|
@@ -8,6 +8,7 @@ module Ooor
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
OPERATORS = ["=", "!=", "<=", "<", ">", ">=", "=?", "=like", "=ilike", "like", "not like", "ilike", "not ilike", "in", "not in", "child_of"]
|
11
|
+
BLACKLIST = %w[id write_date create_date write_ui create_ui]
|
11
12
|
|
12
13
|
module ClassMethods
|
13
14
|
|
@@ -68,28 +69,8 @@ module Ooor
|
|
68
69
|
elsif request.is_a?(Hash)
|
69
70
|
request2 = {}
|
70
71
|
request.each do |k, v|
|
71
|
-
|
72
|
-
if k.to_s.end_with?("_attributes")
|
73
|
-
attrs = []
|
74
|
-
if v.is_a?(Hash)
|
75
|
-
v.each do |key, val|
|
76
|
-
if !val["_destroy"].empty?
|
77
|
-
attrs << [2, val[:id] || val['id']]
|
78
|
-
elsif val[:id] || val['id']
|
79
|
-
attrs << [1, val[:id] || val['id'], cast_request_to_openerp(val)]
|
80
|
-
else
|
81
|
-
attrs << [0, 0, cast_request_to_openerp(val)]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
request2[k.to_s.gsub("_attributes", "")] = attrs
|
87
|
-
else
|
88
|
-
request2[k] = cast_request_to_openerp(v)
|
89
|
-
end
|
72
|
+
request2[k] = cast_request_to_openerp(v)
|
90
73
|
end
|
91
|
-
request2
|
92
|
-
|
93
74
|
else
|
94
75
|
value_to_openerp(request)
|
95
76
|
end
|
@@ -120,72 +101,124 @@ module Ooor
|
|
120
101
|
|
121
102
|
end
|
122
103
|
|
123
|
-
def
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
104
|
+
def sanitize_attribute(skey, value)
|
105
|
+
type = self.class.fields[skey]['type']
|
106
|
+
if type == 'boolean' && value == 1 || value == "1"
|
107
|
+
true
|
108
|
+
elsif type == 'boolean'&& value == 0 || value == "0"
|
109
|
+
false
|
110
|
+
elsif value == false and type != 'boolean'
|
111
|
+
nil
|
112
|
+
else
|
113
|
+
value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def sanitize_association(skey, value)
|
118
|
+
if value.is_a?(Ooor::Base) || value.is_a?(Array) && value.all? {|i| i.is_a?(Ooor::Base)}
|
119
|
+
value
|
120
|
+
elsif value.is_a?(Array) && !self.class.many2one_associations.keys.index(skey)
|
121
|
+
value.reject {|i| i == ''}.map {|i| i.is_a?(String) ? i.to_i : i}
|
122
|
+
elsif value.is_a?(String)
|
123
|
+
sanitize_associatio_as_string(skey, value)
|
124
|
+
else
|
125
|
+
value
|
133
126
|
end
|
134
|
-
|
127
|
+
end
|
128
|
+
|
129
|
+
def sanitize_associatio_as_string(skey, value)
|
130
|
+
if self.class.polymorphic_m2o_associations.has_key?(skey)
|
131
|
+
value
|
132
|
+
elsif self.class.many2one_associations.has_key?(skey)
|
133
|
+
sanitize_m2o_association(value)
|
134
|
+
else
|
135
|
+
value.split(",").map {|i| i.to_i}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def sanitize_m2o_association(value)
|
140
|
+
if value.blank? || value == "0"
|
141
|
+
false
|
142
|
+
else
|
143
|
+
value.to_i
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def to_openerp_hash
|
148
|
+
attributes, associations = get_changed_values
|
149
|
+
associations = cast_associations_to_openerp(associations)
|
150
|
+
attributes.merge(associations)
|
135
151
|
end
|
136
152
|
|
137
|
-
def
|
138
|
-
|
139
|
-
associations
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
if k.end_with?("_ids") && v.is_a?(String)
|
149
|
-
v = v.split(",").map{|i| i.to_i}
|
150
|
-
end
|
151
|
-
associations2[k] = v
|
153
|
+
def get_changed_values
|
154
|
+
attributes = {}
|
155
|
+
associations = {}
|
156
|
+
|
157
|
+
changed.each do |k|
|
158
|
+
if self.class.associations_keys.index(k)
|
159
|
+
associations[k] = @associations[k]#changes[k][1]
|
160
|
+
elsif self.class.fields.has_key?(k)
|
161
|
+
attributes[k]= @attributes[k]
|
162
|
+
elsif !BLACKLIST.index(k)
|
163
|
+
attributes[k] = changes[k][1]
|
152
164
|
end
|
153
165
|
end
|
166
|
+
return attributes, associations
|
167
|
+
end
|
154
168
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
169
|
+
def cast_associations_to_openerp(associations=@associations)
|
170
|
+
associations.each do |k, v|
|
171
|
+
associations[k] = self.cast_association(k, v)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# talk OpenERP cryptic associations API
|
176
|
+
def cast_association(k, v)
|
177
|
+
if self.class.one2many_associations[k]
|
178
|
+
cast_o2m_assocation(v)
|
179
|
+
elsif self.class.many2many_associations[k]
|
180
|
+
[[6, false, (v || []).map {|i| i.is_a?(Base) ? i.id : i}]]
|
181
|
+
elsif self.class.many2one_associations[k]
|
182
|
+
cast_m2o_association(v)
|
170
183
|
end
|
171
|
-
associations2
|
172
184
|
end
|
173
185
|
|
174
|
-
def
|
175
|
-
if
|
176
|
-
|
177
|
-
|
186
|
+
def cast_o2m_assocation(v)
|
187
|
+
if v.is_a?(Hash)
|
188
|
+
cast_o2m_nested_attributes(v)
|
189
|
+
else
|
190
|
+
v.collect do |value|
|
191
|
+
if value.is_a?(Base)
|
178
192
|
[0, 0, value.to_openerp_hash]
|
193
|
+
elsif value.is_a?(Hash)
|
194
|
+
[0, 0, value]
|
179
195
|
else
|
180
|
-
|
181
|
-
[0, 0, value]
|
182
|
-
else
|
183
|
-
[1, value, {}]
|
184
|
-
end
|
196
|
+
[1, value, {}]
|
185
197
|
end
|
186
198
|
end
|
187
|
-
|
188
|
-
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def cast_o2m_nested_attributes(v)
|
203
|
+
v.keys.collect do |key|
|
204
|
+
val = v[key]
|
205
|
+
if !val["_destroy"].blank?
|
206
|
+
[2, val[:id].to_i || val['id']]
|
207
|
+
elsif val[:id] || val['id']
|
208
|
+
[1, val[:id].to_i || val['id'], val]
|
209
|
+
else
|
210
|
+
[0, 0, val]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def cast_m2o_association(v)
|
216
|
+
if v.is_a?(Array)
|
217
|
+
v[0]
|
218
|
+
elsif v.is_a?(Base)
|
219
|
+
v.id
|
220
|
+
else
|
221
|
+
v
|
189
222
|
end
|
190
223
|
end
|
191
224
|
|
data/lib/ooor/version.rb
CHANGED
data/spec/ooor_spec.rb
CHANGED
@@ -42,15 +42,7 @@ describe Ooor do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should be able to load a profile" do
|
45
|
-
|
46
|
-
module_ids.each do |accounting_module_id|
|
47
|
-
mod = IrModuleModule.find(accounting_module_id)
|
48
|
-
unless mod.state == "installed"
|
49
|
-
mod.button_install
|
50
|
-
end
|
51
|
-
end
|
52
|
-
wizard = BaseModuleUpgrade.create
|
53
|
-
wizard.upgrade_module
|
45
|
+
IrModuleModule.install_modules(['sale', 'account_voucher'])
|
54
46
|
@ooor.load_models
|
55
47
|
@ooor.models.keys.should_not be_empty
|
56
48
|
end
|
@@ -68,7 +60,7 @@ describe Ooor do
|
|
68
60
|
describe "Do operations on configured database" do
|
69
61
|
before(:all) do
|
70
62
|
@ooor = Ooor.new(:url => @url, :username => @username, :password => @password, :database => @database,
|
71
|
-
:models => ['res.user', 'res.partner', 'product.product', 'sale.order', 'account.invoice', 'product.category', '
|
63
|
+
:models => ['res.user', 'res.partner', 'product.product', 'sale.order', 'account.invoice', 'product.category', 'ir.cron', 'ir.ui.menu', 'ir.module.module'])
|
72
64
|
end
|
73
65
|
|
74
66
|
describe "Finders operations" do
|
@@ -173,8 +165,16 @@ describe Ooor do
|
|
173
165
|
it "should cast dates properly from OpenERP to Ruby" do
|
174
166
|
o = SaleOrder.find(1)
|
175
167
|
o.date_order.should be_kind_of(Date)
|
176
|
-
|
177
|
-
|
168
|
+
c = IrCron.find(1)
|
169
|
+
c.nextcall.should be_kind_of(DateTime)
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should not load false values in empty strings (for HTML forms)" do
|
173
|
+
ResPartner.first.phone.should be_nil
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should map OpenERP types to Rails types" do
|
177
|
+
(%w[char binary many2one one2many many2many]).each { |t| Ooor::Base.to_rails_type(t).should be_kind_of(Symbol) }
|
178
178
|
end
|
179
179
|
|
180
180
|
it "should be able to call any Class method" do
|
@@ -218,6 +218,12 @@ describe Ooor do
|
|
218
218
|
p.name.should == "testProduct1"
|
219
219
|
end
|
220
220
|
|
221
|
+
it "should properly change value when m2o is set" do
|
222
|
+
p = ProductProduct.find(:first)
|
223
|
+
p.categ_id = 7
|
224
|
+
p.categ_id.id.should == 7
|
225
|
+
end
|
226
|
+
|
221
227
|
it "should be able to create a product" do
|
222
228
|
p = ProductProduct.create(:name => "testProduct1", :categ_id => 1)
|
223
229
|
ProductProduct.find(p.id).categ_id.id.should == 1
|
@@ -235,12 +241,12 @@ describe Ooor do
|
|
235
241
|
u.save
|
236
242
|
u.id.should_not be_nil
|
237
243
|
u.name.should == "joe"
|
238
|
-
u.destroy
|
244
|
+
u.destroy.should be_kind_of(ResUsers)
|
239
245
|
end
|
240
246
|
|
241
247
|
it "should be able to create an order" do
|
242
|
-
|
243
|
-
|
248
|
+
p_id = ResPartner.search([['name', 'ilike', 'Agrolait']])[0]
|
249
|
+
o = SaleOrder.create(partner_id: p_id, partner_invoice_id: p_id, partner_shipping_id: p_id, pricelist_id: 1)
|
244
250
|
o.id.should be_kind_of(Integer)
|
245
251
|
end
|
246
252
|
|
@@ -268,7 +274,7 @@ describe Ooor do
|
|
268
274
|
|
269
275
|
it "should use default fields on creation" do
|
270
276
|
p = ProductProduct.new
|
271
|
-
p.
|
277
|
+
p.categ_id.should be_kind_of(ProductCategory)
|
272
278
|
end
|
273
279
|
|
274
280
|
it "should skipped inherited default fields properly, for instance at product variant creation" do
|
@@ -335,16 +341,44 @@ describe Ooor do
|
|
335
341
|
p.taxes_id_ids.should be_kind_of(Array)
|
336
342
|
end
|
337
343
|
|
338
|
-
it "should support Rails nested attributes" do
|
344
|
+
it "should support Rails nested attributes methods" do
|
339
345
|
so = SaleOrder.find :first
|
340
346
|
so.respond_to?(:order_line_attributes).should be_true
|
341
347
|
so.respond_to?(:order_line_attributes=).should be_true
|
342
348
|
end
|
343
349
|
|
350
|
+
it "should support CRUD on o2m via nested attributes" do
|
351
|
+
p = ProductProduct.create(name:'Ooor product with packages')
|
352
|
+
p.packaging_attributes = {'1' => {name: 'pack1'}, '2' => {name: 'pack2'}}
|
353
|
+
p.save
|
354
|
+
p = ProductProduct.find p.id
|
355
|
+
pack1 = p.packaging[0]
|
356
|
+
pack2 = p.packaging[1]
|
357
|
+
pack2.name.should == 'pack2'
|
358
|
+
p.packaging_attributes = {'1' => {name: 'pack1', '_destroy'=> true, id: pack1.id}, '2' => {name: 'pack2_modified', id: pack2.id}}
|
359
|
+
p.save
|
360
|
+
p.packaging.size.should == 1
|
361
|
+
p.packaging[0].name.should == 'pack2_modified'
|
362
|
+
end
|
363
|
+
|
344
364
|
it "should be able to call build upon a o2m association" do
|
345
365
|
so = SaleOrder.find :first
|
346
366
|
so.order_line.build().should be_kind_of(SaleOrderLine)
|
347
367
|
end
|
368
|
+
|
369
|
+
it "should recast string m2o string id to an integer (it happens in forms)" do
|
370
|
+
uom_id = @ooor.const_get('product.uom').search()[0]
|
371
|
+
p = ProductProduct.new(name: "z recast id", uom_id: uom_id.to_s)
|
372
|
+
p.save
|
373
|
+
p.uom_id.id.should == uom_id
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should recast string m2m string ids to an array of integer (it happens in forms)" do
|
377
|
+
categ_ids = @ooor.const_get('res.partner.category').search()[0..1]
|
378
|
+
p = ResPartner.new(name: "z recast ids", category_id: categ_ids.join(','))
|
379
|
+
p.save
|
380
|
+
p.category_id.map{|c| c.id}.should == categ_ids
|
381
|
+
end
|
348
382
|
end
|
349
383
|
|
350
384
|
describe "Fields validations" do
|
@@ -354,6 +388,28 @@ describe Ooor do
|
|
354
388
|
p.save.should == false
|
355
389
|
p.errors.messages[:ean13].should_not be_nil
|
356
390
|
end
|
391
|
+
|
392
|
+
it "should list all available fields when you call an invalid field" do
|
393
|
+
expect { ProductProduct.find(1).unexisting_field_or_method }.to raise_error(Ooor::UnknownAttributeOrAssociationError, /AVAILABLE FIELDS/)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
describe "Life cycle Callbacks" do
|
398
|
+
include Ooor
|
399
|
+
|
400
|
+
it "should call customized before_save callback" do
|
401
|
+
expect do
|
402
|
+
Ooor.xtend('ir.ui.menu') do
|
403
|
+
before_save do
|
404
|
+
raise 'before_save_called'
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
with_ooor_session username: 'demo', password: 'demo' do |session|
|
409
|
+
session['ir.ui.menu'].first.save
|
410
|
+
end
|
411
|
+
end.to raise_error(RuntimeError, /before_save_called/)
|
412
|
+
end
|
357
413
|
end
|
358
414
|
|
359
415
|
describe "ARel emulation" do
|
@@ -361,13 +417,37 @@ describe Ooor do
|
|
361
417
|
ResUsers.all.should be_kind_of(Array)
|
362
418
|
end
|
363
419
|
|
420
|
+
it "should have a 'first' method" do
|
421
|
+
ResUsers.first.id.should == 1
|
422
|
+
end
|
423
|
+
|
424
|
+
it "should have a 'last' method" do
|
425
|
+
ResUsers.last.id.should == ResUsers.find(:last).id
|
426
|
+
end
|
427
|
+
|
364
428
|
it "should be ready for Kaminari pagination via ARel scoping" do
|
365
429
|
num = 2
|
366
430
|
default_per_page = 5
|
367
|
-
collection = ProductProduct.limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1))
|
431
|
+
collection = ProductProduct.where(active: true).limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1)).order("categ_id")
|
368
432
|
collection.all(fields:['name']).should be_kind_of(Array)
|
369
433
|
collection.all.size.should == 5
|
370
434
|
end
|
435
|
+
|
436
|
+
it "should support name_search in ARel (used in association widgets with Ooorest)" do
|
437
|
+
Ooor.default_session.const_get('product.category').all(name_search: 'Com')[0].name.should == "All products / Saleable / Components"
|
438
|
+
end
|
439
|
+
|
440
|
+
it "should be possible to invoke batch methods on relations" do
|
441
|
+
Ooor.default_session.const_get('product.product').where(type: 'service').write(type: 'service').should == true
|
442
|
+
end
|
443
|
+
|
444
|
+
it "should forward Array methods to the Array" do
|
445
|
+
Ooor.default_session.const_get('product.product').where(type: 'service').size.should be_kind_of(Integer)
|
446
|
+
end
|
447
|
+
|
448
|
+
it "should support reloading relation" do
|
449
|
+
Ooor.default_session.const_get('product.product').where(type: 'service').reload.all.should be_kind_of(Array)
|
450
|
+
end
|
371
451
|
end
|
372
452
|
|
373
453
|
describe "report support" do
|
@@ -383,12 +463,12 @@ describe Ooor do
|
|
383
463
|
inv.state.should == "draft"
|
384
464
|
inv.wkf_action('invoice_open')
|
385
465
|
inv.state.should == "open"
|
386
|
-
voucher =
|
387
|
-
voucher.on_change("onchange_partner_id", [], :partner_id, inv.partner_id.id,
|
466
|
+
voucher = @ooor.const_get('account.voucher').new({:amount=>inv.amount_total, :type=>"receipt", :partner_id => inv.partner_id.id}, {"default_amount"=>inv.amount_total, "invoice_id"=>inv.id})
|
467
|
+
voucher.on_change("onchange_partner_id", [], :partner_id, inv.partner_id.id, @ooor.const_get('account.journal').find('account.bank_journal').id, 0.0, 1, 'receipt', false)
|
388
468
|
voucher.save
|
389
|
-
voucher.wkf_action 'proforma_voucher'
|
469
|
+
# voucher.wkf_action 'proforma_voucher'
|
390
470
|
|
391
|
-
inv.reload
|
471
|
+
# inv.reload
|
392
472
|
end
|
393
473
|
|
394
474
|
it "should be possible to call resource actions and workflow actions" do
|
@@ -443,11 +523,19 @@ describe Ooor do
|
|
443
523
|
Ooor.session_handler.reset!() # alias isn't part of the connection spec, we don't want connectio reuse here
|
444
524
|
with_ooor_session(:url => @url, :database => @database, :username => @username, :password => @password, :aliases => {en_US: {products: 'product.product'}}, :param_keys => {'product.product' => 'name'}) do |session|
|
445
525
|
session['products'].search().should be_kind_of(Array)
|
526
|
+
session['product.product'].alias.should == 'products'
|
446
527
|
end
|
447
528
|
end
|
448
529
|
|
449
|
-
it "should
|
530
|
+
it "should have a to_param method" do
|
450
531
|
Ooor.session_handler.reset!() # alias isn't part of the connection spec, we don't want connectio reuse here
|
532
|
+
with_ooor_session(:url => @url, :database => @database, :username => @username, :password => @password, :aliases => {en_US: {products: 'product.product'}}, :param_keys => {'product.product' => 'name'}) do |session|
|
533
|
+
session['product.product'].find(:first).to_param.should be_kind_of(String)
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
it "should find by permalink" do
|
538
|
+
Ooor.session_handler.reset!() # alias isn't part of the connection spec, we don't want connection reuse here
|
451
539
|
with_ooor_session(:url => @url, :database => @database, :username => @username, :password => @password, :aliases => {en_US: {products: 'product.product'}}, :param_keys => {'product.product' => 'name'}) do |session|
|
452
540
|
lang = Ooor::Locale.to_erp_locale('en')
|
453
541
|
session['products'].find_by_permalink('Service', context: {'lang' => lang}, fields: ['name']).should be_kind_of(Ooor::Base)
|
@@ -455,24 +543,33 @@ describe Ooor do
|
|
455
543
|
end
|
456
544
|
end
|
457
545
|
|
458
|
-
describe "Ative-Record like
|
546
|
+
describe "Ative-Record like Reflections" do
|
459
547
|
before(:all) do
|
460
|
-
@ooor = Ooor.new(:url => @url, :username => @username, :password => @password, :database => @database, :models => ['product.product'], :reload => true)
|
548
|
+
@ooor = Ooor.new(:url => @url, :username => @username, :password => @password, :database => @database, :models => ['product.product', 'product.category'], :reload => true)
|
461
549
|
end
|
462
550
|
|
463
|
-
it "should test correct class attributes" do
|
551
|
+
it "should test correct class attributes of ActiveRecord Reflection" do
|
464
552
|
object = Ooor::Reflection::AssociationReflection.new(:test, :people, {}, nil)
|
465
553
|
object.name.should == :people
|
466
554
|
object.macro.should == :test
|
467
555
|
object.options.should == {}
|
468
556
|
end
|
469
557
|
|
470
|
-
it "should test correct class name matching
|
558
|
+
it "should test correct class name matching with class name" do
|
471
559
|
object = Ooor::Reflection::AssociationReflection.new(:test, 'product_product', {class_name: 'product.product'}, nil)
|
472
560
|
object.connection = @ooor
|
473
561
|
object.klass.should == ProductProduct
|
474
562
|
end
|
475
563
|
|
564
|
+
it "should reflect on association (used in simple_form, cocoon...)" do
|
565
|
+
reflection = ProductProduct.reflect_on_association(:categ_id)
|
566
|
+
reflection.should be_kind_of(Ooor::Reflection::AssociationReflection)
|
567
|
+
reflection.klass.should == ProductCategory
|
568
|
+
end
|
569
|
+
|
570
|
+
it "should support column_for_attribute (used by simple_form)" do
|
571
|
+
@ooor.const_get('ir.cron').find(:first).column_for_attribute('name')[:type].should == :string
|
572
|
+
end
|
476
573
|
end
|
477
574
|
|
478
575
|
describe "Multi-instance and class name scoping" do
|
@@ -510,6 +607,15 @@ describe Ooor do
|
|
510
607
|
session['res.users'].search().should be_kind_of(Array)
|
511
608
|
end
|
512
609
|
end
|
610
|
+
|
611
|
+
it "should recover from expired sessions" do
|
612
|
+
with_ooor_session(:url => @url, :username => @username, :password => @password, :database => @database) do |session|
|
613
|
+
user_obj = session['res.users']
|
614
|
+
user_obj.search().should be_kind_of(Array)
|
615
|
+
session.web_session[:session_id] = 'invalid'
|
616
|
+
user_obj.search().should be_kind_of(Array)
|
617
|
+
end
|
618
|
+
end
|
513
619
|
end
|
514
620
|
|
515
621
|
|