PyOdoo 0.5.6__tar.gz → 0.5.8__tar.gz
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.
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/PKG-INFO +2 -1
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/PyOdoo.egg-info/PKG-INFO +2 -1
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/PyOdoo.egg-info/SOURCES.txt +1 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/compare_type.py +10 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/constants.py +1 -1
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/samples/contacts.py +5 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/v12/model.py +29 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/setup.cfg +1 -0
- PyOdoo-0.5.8/tests/test_compare_types.py +393 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/tests/test_contacts.py +73 -47
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/LICENSE +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/PyOdoo.egg-info/dependency_links.txt +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/PyOdoo.egg-info/top_level.txt +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/README.md +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/__init__.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/active_status_choice.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/boolean_operator.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/filter.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/message_subtype.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/samples/__init__.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/samples/awaitable.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/samples/contacts_async.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/v12/__init__.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyodoo/v12/api.py +0 -0
- {PyOdoo-0.5.6 → PyOdoo-0.5.8}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyOdoo
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
4
4
|
Summary: API for Odoo
|
|
5
5
|
Home-page: http://www.muflone.com/pyodoo/
|
|
6
6
|
Author: Fabio Castelli
|
|
@@ -13,6 +13,7 @@ Classifier: Operating System :: OS Independent
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
18
|
Description-Content-Type: text/markdown
|
|
18
19
|
License-File: LICENSE
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyOdoo
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
4
4
|
Summary: API for Odoo
|
|
5
5
|
Home-page: http://www.muflone.com/pyodoo/
|
|
6
6
|
Author: Fabio Castelli
|
|
@@ -13,6 +13,7 @@ Classifier: Operating System :: OS Independent
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
18
|
Description-Content-Type: text/markdown
|
|
18
19
|
License-File: LICENSE
|
|
@@ -32,3 +32,13 @@ class CompareType(object):
|
|
|
32
32
|
NOT_IN = 'not in'
|
|
33
33
|
CONTAINS = 'ilike'
|
|
34
34
|
CONTAINS_NOT = 'not ilike'
|
|
35
|
+
NOT_CONTAINS = 'not ilike'
|
|
36
|
+
LIKE = 'like'
|
|
37
|
+
NOT_LIKE = 'not like'
|
|
38
|
+
ILIKE = 'ilike'
|
|
39
|
+
NOT_ILIKE = 'not ilike'
|
|
40
|
+
RAW_LIKE = '=like'
|
|
41
|
+
RAW_ILIKE = '=ilike'
|
|
42
|
+
UNSET_OR_EQUAL = '=?'
|
|
43
|
+
CHILD_OF = 'child_of'
|
|
44
|
+
PARENT_OF = 'parent_of'
|
|
@@ -72,6 +72,11 @@ results = model.filter(filters=filters,
|
|
|
72
72
|
fields=('id', 'name', 'country_id'))
|
|
73
73
|
print('filter', results)
|
|
74
74
|
|
|
75
|
+
# Find first record by filters
|
|
76
|
+
results = model.first(filters=filters,
|
|
77
|
+
fields=('id', 'name', 'country_id'))
|
|
78
|
+
print('first', results)
|
|
79
|
+
|
|
75
80
|
# Get all the record
|
|
76
81
|
results = model.all(fields=('id', 'name'),
|
|
77
82
|
limit=1000)
|
|
@@ -315,6 +315,35 @@ class Model(object):
|
|
|
315
315
|
options=options)
|
|
316
316
|
return results
|
|
317
317
|
|
|
318
|
+
def first(self,
|
|
319
|
+
filters: list[Union[BooleanOperator, Filter]],
|
|
320
|
+
is_active: ActiveStatusChoice = ActiveStatusChoice.NOT_SET,
|
|
321
|
+
fields: tuple[str, ...] = None,
|
|
322
|
+
options: dict[str, Any] = None,
|
|
323
|
+
limit: Optional[int] = None,
|
|
324
|
+
offset: Optional[int] = None,
|
|
325
|
+
order: Optional[str] = None) -> Optional[dict[str, Any]]:
|
|
326
|
+
"""
|
|
327
|
+
Find the first row from a model using some filters
|
|
328
|
+
|
|
329
|
+
:param filters: List of filters used for searching the data
|
|
330
|
+
:param is_active: Additional filter for active field
|
|
331
|
+
:param fields: Tuple with the fields to include in the response
|
|
332
|
+
:param options: Dictionary with options to use
|
|
333
|
+
:param limit: Maximum number of results count
|
|
334
|
+
:param offset: Starting record number to fetch the data
|
|
335
|
+
:param order: Ordering clause
|
|
336
|
+
:return: List of dictionaries with the requested fields
|
|
337
|
+
"""
|
|
338
|
+
results = self.filter(filters=filters,
|
|
339
|
+
is_active=is_active,
|
|
340
|
+
fields=fields,
|
|
341
|
+
options=options,
|
|
342
|
+
limit=limit,
|
|
343
|
+
offset=offset,
|
|
344
|
+
order=order)
|
|
345
|
+
return results[0] if results else None
|
|
346
|
+
|
|
318
347
|
def count(self,
|
|
319
348
|
filters: list[Union[BooleanOperator, Filter]],
|
|
320
349
|
is_active: ActiveStatusChoice = ActiveStatusChoice.NOT_SET,
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Project: PyOdoo
|
|
3
|
+
# Description: API for Odoo
|
|
4
|
+
# Author: Fabio Castelli (Muflone) <muflone@muflone.com>
|
|
5
|
+
# Copyright: 2021-2023 Fabio Castelli
|
|
6
|
+
# License: GPL-3+
|
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU General Public License
|
|
18
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
##
|
|
20
|
+
|
|
21
|
+
import unittest
|
|
22
|
+
|
|
23
|
+
from pyodoo import CompareType, Filter
|
|
24
|
+
|
|
25
|
+
import utility
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestCaseCompareTypes(unittest.TestCase):
|
|
29
|
+
@classmethod
|
|
30
|
+
def setUpClass(cls):
|
|
31
|
+
"""
|
|
32
|
+
Model object preparation
|
|
33
|
+
"""
|
|
34
|
+
cls.model = utility.get_model_from_demo(model_name='product.template')
|
|
35
|
+
cls.model.authenticate()
|
|
36
|
+
|
|
37
|
+
def test_01_filter_equal(self) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Search some rows using filters using compare EQUAL
|
|
40
|
+
"""
|
|
41
|
+
filters = [Filter(field='name',
|
|
42
|
+
compare_type=CompareType.EQUAL,
|
|
43
|
+
value='Mozzarella Sandwich')]
|
|
44
|
+
results = self.model.search(filters=filters)
|
|
45
|
+
# Check if the results are not None
|
|
46
|
+
self.assertIsNotNone(results)
|
|
47
|
+
# Check if the results list has exactly one item
|
|
48
|
+
self.assertEqual(len(results), 1)
|
|
49
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
50
|
+
self.assertIn(75, results)
|
|
51
|
+
|
|
52
|
+
def test_02_filter_not_equal(self) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Search some rows using filters using compare NOT_EQUAL
|
|
55
|
+
"""
|
|
56
|
+
filters = [Filter(field='name',
|
|
57
|
+
compare_type=CompareType.CONTAINS,
|
|
58
|
+
value='Sandwich'),
|
|
59
|
+
Filter(field='name',
|
|
60
|
+
compare_type=CompareType.NOT_EQUAL,
|
|
61
|
+
value='Mozzarella Sandwich')]
|
|
62
|
+
results = self.model.search(filters=filters)
|
|
63
|
+
# Check if the results are not None
|
|
64
|
+
self.assertIsNotNone(results)
|
|
65
|
+
# Check if the results list has exactly three items
|
|
66
|
+
self.assertEqual(len(results), 3)
|
|
67
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
68
|
+
self.assertNotIn(75, results)
|
|
69
|
+
|
|
70
|
+
def test_03_filter_greater(self) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Search some rows using filters using compare GREATER
|
|
73
|
+
"""
|
|
74
|
+
filters = [Filter(field='name',
|
|
75
|
+
compare_type=CompareType.CONTAINS,
|
|
76
|
+
value='Sandwich'),
|
|
77
|
+
Filter(field='name',
|
|
78
|
+
compare_type=CompareType.GREATER,
|
|
79
|
+
value='Mozzarella Sandwich')]
|
|
80
|
+
results = self.model.search(filters=filters)
|
|
81
|
+
# Check if the results are not None
|
|
82
|
+
self.assertIsNotNone(results)
|
|
83
|
+
# Check if the results list has exactly one item
|
|
84
|
+
self.assertEqual(len(results), 1)
|
|
85
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
86
|
+
self.assertNotIn(75, results)
|
|
87
|
+
|
|
88
|
+
def test_04_filter_greater_equal(self) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Search some rows using filters using compare GREATER_EQ
|
|
91
|
+
"""
|
|
92
|
+
filters = [Filter(field='name',
|
|
93
|
+
compare_type=CompareType.CONTAINS,
|
|
94
|
+
value='Sandwich'),
|
|
95
|
+
Filter(field='name',
|
|
96
|
+
compare_type=CompareType.GREATER_EQ,
|
|
97
|
+
value='Mozzarella Sandwich')]
|
|
98
|
+
results = self.model.search(filters=filters)
|
|
99
|
+
# Check if the results are not None
|
|
100
|
+
self.assertIsNotNone(results)
|
|
101
|
+
# Check if the results list has exactly two items
|
|
102
|
+
self.assertEqual(len(results), 2)
|
|
103
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
104
|
+
self.assertIn(75, results)
|
|
105
|
+
|
|
106
|
+
def test_05_filter_lower(self) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Search some rows using filters using compare LOWER
|
|
109
|
+
"""
|
|
110
|
+
filters = [Filter(field='name',
|
|
111
|
+
compare_type=CompareType.CONTAINS,
|
|
112
|
+
value='Sandwich'),
|
|
113
|
+
Filter(field='name',
|
|
114
|
+
compare_type=CompareType.LOWER,
|
|
115
|
+
value='Mozzarella Sandwich')]
|
|
116
|
+
results = self.model.search(filters=filters)
|
|
117
|
+
# Check if the results are not None
|
|
118
|
+
self.assertIsNotNone(results)
|
|
119
|
+
# Check if the results list has exactly two items
|
|
120
|
+
self.assertEqual(len(results), 2)
|
|
121
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
122
|
+
self.assertNotIn(75, results)
|
|
123
|
+
|
|
124
|
+
def test_06_filter_lower_equal(self) -> None:
|
|
125
|
+
"""
|
|
126
|
+
Search some rows using filters using compare LOWER_EQ
|
|
127
|
+
"""
|
|
128
|
+
filters = [Filter(field='name',
|
|
129
|
+
compare_type=CompareType.CONTAINS,
|
|
130
|
+
value='Sandwich'),
|
|
131
|
+
Filter(field='name',
|
|
132
|
+
compare_type=CompareType.LOWER_EQ,
|
|
133
|
+
value='Mozzarella Sandwich')]
|
|
134
|
+
results = self.model.search(filters=filters)
|
|
135
|
+
# Check if the results are not None
|
|
136
|
+
self.assertIsNotNone(results)
|
|
137
|
+
# Check if the results list has exactly three items
|
|
138
|
+
self.assertEqual(len(results), 3)
|
|
139
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
140
|
+
self.assertIn(75, results)
|
|
141
|
+
|
|
142
|
+
def test_07_filter_in(self) -> None:
|
|
143
|
+
"""
|
|
144
|
+
Search some rows using filters using compare IN
|
|
145
|
+
"""
|
|
146
|
+
filters = [Filter(field='name',
|
|
147
|
+
compare_type=CompareType.CONTAINS,
|
|
148
|
+
value='Sandwich'),
|
|
149
|
+
Filter(field='name',
|
|
150
|
+
compare_type=CompareType.IN,
|
|
151
|
+
value=('Club Sandwich', 'Mozzarella Sandwich'))]
|
|
152
|
+
results = self.model.search(filters=filters)
|
|
153
|
+
# Check if the results are not None
|
|
154
|
+
self.assertIsNotNone(results)
|
|
155
|
+
# Check if the results list has exactly two items
|
|
156
|
+
self.assertEqual(len(results), 2)
|
|
157
|
+
# Check if the results list contains the Club Sandwich
|
|
158
|
+
self.assertIn(76, results)
|
|
159
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
160
|
+
self.assertIn(75, results)
|
|
161
|
+
|
|
162
|
+
def test_08_filter_not_in(self) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Search some rows using filters using compare NOT_IN
|
|
165
|
+
"""
|
|
166
|
+
filters = [Filter(field='name',
|
|
167
|
+
compare_type=CompareType.CONTAINS,
|
|
168
|
+
value='Sandwich'),
|
|
169
|
+
Filter(field='name',
|
|
170
|
+
compare_type=CompareType.NOT_IN,
|
|
171
|
+
value=('Club Sandwich', 'Mozzarella Sandwich'))]
|
|
172
|
+
results = self.model.search(filters=filters)
|
|
173
|
+
# Check if the results are not None
|
|
174
|
+
self.assertIsNotNone(results)
|
|
175
|
+
# Check if the results list has exactly two items
|
|
176
|
+
self.assertEqual(len(results), 2)
|
|
177
|
+
# Check if the results list doesn't contain the Club Sandwich
|
|
178
|
+
self.assertNotIn(76, results)
|
|
179
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
180
|
+
self.assertNotIn(75, results)
|
|
181
|
+
|
|
182
|
+
def test_09_filter_contains(self) -> None:
|
|
183
|
+
"""
|
|
184
|
+
Search some rows using filters using compare CONTAINS
|
|
185
|
+
"""
|
|
186
|
+
filters = [Filter(field='name',
|
|
187
|
+
compare_type=CompareType.CONTAINS,
|
|
188
|
+
value='Sandwich')]
|
|
189
|
+
results = self.model.search(filters=filters)
|
|
190
|
+
# Check if the results are not None
|
|
191
|
+
self.assertIsNotNone(results)
|
|
192
|
+
# Check if the results list has exactly four items
|
|
193
|
+
self.assertEqual(len(results), 4)
|
|
194
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
195
|
+
self.assertIn(75, results)
|
|
196
|
+
|
|
197
|
+
def test_10_filter_contains_not(self) -> None:
|
|
198
|
+
"""
|
|
199
|
+
Search some rows using filters using compare CONTAINS_NOT
|
|
200
|
+
"""
|
|
201
|
+
filters = [Filter(field='name',
|
|
202
|
+
compare_type=CompareType.CONTAINS,
|
|
203
|
+
value='Sandwich'),
|
|
204
|
+
Filter(field='name',
|
|
205
|
+
compare_type=CompareType.CONTAINS_NOT,
|
|
206
|
+
value='mozzarella')]
|
|
207
|
+
results = self.model.search(filters=filters)
|
|
208
|
+
# Check if the results are not None
|
|
209
|
+
self.assertIsNotNone(results)
|
|
210
|
+
# Check if the results list has exactly three items
|
|
211
|
+
self.assertEqual(len(results), 3)
|
|
212
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
213
|
+
self.assertNotIn(75, results)
|
|
214
|
+
|
|
215
|
+
def test_11_filter_not_contains(self) -> None:
|
|
216
|
+
"""
|
|
217
|
+
Search some rows using filters using compare NOT_CONTAINS
|
|
218
|
+
"""
|
|
219
|
+
filters = [Filter(field='name',
|
|
220
|
+
compare_type=CompareType.CONTAINS,
|
|
221
|
+
value='Sandwich'),
|
|
222
|
+
Filter(field='name',
|
|
223
|
+
compare_type=CompareType.NOT_CONTAINS,
|
|
224
|
+
value='mozzarella')]
|
|
225
|
+
results = self.model.search(filters=filters)
|
|
226
|
+
# Check if the results are not None
|
|
227
|
+
self.assertIsNotNone(results)
|
|
228
|
+
# Check if the results list has exactly three items
|
|
229
|
+
self.assertEqual(len(results), 3)
|
|
230
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
231
|
+
self.assertNotIn(75, results)
|
|
232
|
+
|
|
233
|
+
def test_12_filter_like(self) -> None:
|
|
234
|
+
"""
|
|
235
|
+
Search some rows using filters using compare LIKE
|
|
236
|
+
"""
|
|
237
|
+
filters = [Filter(field='name',
|
|
238
|
+
compare_type=CompareType.CONTAINS,
|
|
239
|
+
value='Sandwich'),
|
|
240
|
+
Filter(field='name',
|
|
241
|
+
compare_type=CompareType.LIKE,
|
|
242
|
+
value='Mozzarella')]
|
|
243
|
+
results = self.model.search(filters=filters)
|
|
244
|
+
# Check if the results are not None
|
|
245
|
+
self.assertIsNotNone(results)
|
|
246
|
+
# Check if the results list has exactly one item
|
|
247
|
+
self.assertEqual(len(results), 1)
|
|
248
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
249
|
+
self.assertIn(75, results)
|
|
250
|
+
|
|
251
|
+
def test_13_filter_not_like(self) -> None:
|
|
252
|
+
"""
|
|
253
|
+
Search some rows using filters using compare NOT_LIKE
|
|
254
|
+
"""
|
|
255
|
+
filters = [Filter(field='name',
|
|
256
|
+
compare_type=CompareType.CONTAINS,
|
|
257
|
+
value='Sandwich'),
|
|
258
|
+
Filter(field='name',
|
|
259
|
+
compare_type=CompareType.NOT_LIKE,
|
|
260
|
+
value='Mozzarella')]
|
|
261
|
+
results = self.model.search(filters=filters)
|
|
262
|
+
# Check if the results are not None
|
|
263
|
+
self.assertIsNotNone(results)
|
|
264
|
+
# Check if the results list has exactly three items
|
|
265
|
+
self.assertEqual(len(results), 3)
|
|
266
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
267
|
+
self.assertNotIn(75, results)
|
|
268
|
+
|
|
269
|
+
def test_14_filter_ilike(self) -> None:
|
|
270
|
+
"""
|
|
271
|
+
Search some rows using filters using compare ILIKE
|
|
272
|
+
"""
|
|
273
|
+
filters = [Filter(field='name',
|
|
274
|
+
compare_type=CompareType.CONTAINS,
|
|
275
|
+
value='Sandwich'),
|
|
276
|
+
Filter(field='name',
|
|
277
|
+
compare_type=CompareType.ILIKE,
|
|
278
|
+
value='mozzarella')]
|
|
279
|
+
results = self.model.search(filters=filters)
|
|
280
|
+
# Check if the results are not None
|
|
281
|
+
self.assertIsNotNone(results)
|
|
282
|
+
# Check if the results list has exactly one item
|
|
283
|
+
self.assertEqual(len(results), 1)
|
|
284
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
285
|
+
self.assertIn(75, results)
|
|
286
|
+
|
|
287
|
+
def test_15_filter_not_ilike(self) -> None:
|
|
288
|
+
"""
|
|
289
|
+
Search some rows using filters using compare NOT_ILIKE
|
|
290
|
+
"""
|
|
291
|
+
filters = [Filter(field='name',
|
|
292
|
+
compare_type=CompareType.CONTAINS,
|
|
293
|
+
value='Sandwich'),
|
|
294
|
+
Filter(field='name',
|
|
295
|
+
compare_type=CompareType.NOT_ILIKE,
|
|
296
|
+
value='mozzarella')]
|
|
297
|
+
results = self.model.search(filters=filters)
|
|
298
|
+
# Check if the results are not None
|
|
299
|
+
self.assertIsNotNone(results)
|
|
300
|
+
# Check if the results list has exactly three items
|
|
301
|
+
self.assertEqual(len(results), 3)
|
|
302
|
+
# Check if the results list doesn't contain the Mozzarella Sandwich
|
|
303
|
+
self.assertNotIn(75, results)
|
|
304
|
+
|
|
305
|
+
def test_16_filter_raw_like(self) -> None:
|
|
306
|
+
"""
|
|
307
|
+
Search some rows using filters using compare RAW_LIKE
|
|
308
|
+
"""
|
|
309
|
+
filters = [Filter(field='name',
|
|
310
|
+
compare_type=CompareType.CONTAINS,
|
|
311
|
+
value='Sandwich'),
|
|
312
|
+
Filter(field='name',
|
|
313
|
+
compare_type=CompareType.RAW_LIKE,
|
|
314
|
+
value='Mozzarella %')]
|
|
315
|
+
results = self.model.search(filters=filters)
|
|
316
|
+
# Check if the results are not None
|
|
317
|
+
self.assertIsNotNone(results)
|
|
318
|
+
# Check if the results list has exactly one item
|
|
319
|
+
self.assertEqual(len(results), 1)
|
|
320
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
321
|
+
self.assertIn(75, results)
|
|
322
|
+
|
|
323
|
+
def test_17_filter_raw_ilike(self) -> None:
|
|
324
|
+
"""
|
|
325
|
+
Search some rows using filters using compare RAW_ILIKE
|
|
326
|
+
"""
|
|
327
|
+
filters = [Filter(field='name',
|
|
328
|
+
compare_type=CompareType.CONTAINS,
|
|
329
|
+
value='Sandwich'),
|
|
330
|
+
Filter(field='name',
|
|
331
|
+
compare_type=CompareType.RAW_ILIKE,
|
|
332
|
+
value='mozzarella %')]
|
|
333
|
+
results = self.model.search(filters=filters)
|
|
334
|
+
# Check if the results are not None
|
|
335
|
+
self.assertIsNotNone(results)
|
|
336
|
+
# Check if the results list has exactly one item
|
|
337
|
+
self.assertEqual(len(results), 1)
|
|
338
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
339
|
+
self.assertIn(75, results)
|
|
340
|
+
|
|
341
|
+
def test_18_filter_unset_or_equal(self) -> None:
|
|
342
|
+
"""
|
|
343
|
+
Search some rows using filters using compare UNSET_OR_EQUAL
|
|
344
|
+
"""
|
|
345
|
+
filters = [Filter(field='name',
|
|
346
|
+
compare_type=CompareType.CONTAINS,
|
|
347
|
+
value='Sandwich'),
|
|
348
|
+
Filter(field='uom_id',
|
|
349
|
+
compare_type=CompareType.UNSET_OR_EQUAL,
|
|
350
|
+
value=1)]
|
|
351
|
+
results = self.model.search(filters=filters)
|
|
352
|
+
# Check if the results are not None
|
|
353
|
+
self.assertIsNotNone(results)
|
|
354
|
+
# Check if the results list has exactly four items
|
|
355
|
+
self.assertEqual(len(results), 4)
|
|
356
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
357
|
+
self.assertIn(75, results)
|
|
358
|
+
|
|
359
|
+
def test_19_filter_child_of(self) -> None:
|
|
360
|
+
"""
|
|
361
|
+
Search some rows using filters using compare CHILD_OF
|
|
362
|
+
"""
|
|
363
|
+
filters = [Filter(field='name',
|
|
364
|
+
compare_type=CompareType.CONTAINS,
|
|
365
|
+
value='Sandwich'),
|
|
366
|
+
Filter(field='categ_id',
|
|
367
|
+
compare_type=CompareType.CHILD_OF,
|
|
368
|
+
value='PoS')]
|
|
369
|
+
results = self.model.search(filters=filters)
|
|
370
|
+
# Check if the results are not None
|
|
371
|
+
self.assertIsNotNone(results)
|
|
372
|
+
# Check if the results list has exactly four items
|
|
373
|
+
self.assertEqual(len(results), 4)
|
|
374
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
375
|
+
self.assertIn(75, results)
|
|
376
|
+
|
|
377
|
+
def test_20_filter_parent_of(self) -> None:
|
|
378
|
+
"""
|
|
379
|
+
Search some rows using filters using compare PARENT_OF
|
|
380
|
+
"""
|
|
381
|
+
filters = [Filter(field='name',
|
|
382
|
+
compare_type=CompareType.CONTAINS,
|
|
383
|
+
value='Sandwich'),
|
|
384
|
+
Filter(field='categ_id',
|
|
385
|
+
compare_type=CompareType.PARENT_OF,
|
|
386
|
+
value='Food')]
|
|
387
|
+
results = self.model.search(filters=filters)
|
|
388
|
+
# Check if the results are not None
|
|
389
|
+
self.assertIsNotNone(results)
|
|
390
|
+
# Check if the results list has exactly four items
|
|
391
|
+
self.assertEqual(len(results), 4)
|
|
392
|
+
# Check if the results list contains the Mozzarella Sandwich
|
|
393
|
+
self.assertIn(75, results)
|
|
@@ -29,6 +29,8 @@ from pyodoo import (ActiveStatusChoice,
|
|
|
29
29
|
from pyodoo.constants import APP_AUTHOR_EMAIL, APP_NAME, APP_VERSION
|
|
30
30
|
from pyodoo.v12 import Model
|
|
31
31
|
|
|
32
|
+
import utility
|
|
33
|
+
|
|
32
34
|
|
|
33
35
|
class TestCaseContacts(unittest.TestCase):
|
|
34
36
|
@classmethod
|
|
@@ -36,24 +38,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
36
38
|
"""
|
|
37
39
|
Model object preparation
|
|
38
40
|
"""
|
|
39
|
-
|
|
40
|
-
try:
|
|
41
|
-
info = xmlrpc.client.ServerProxy(
|
|
42
|
-
uri='https://demo.odoo.com/start').start()
|
|
43
|
-
except xmlrpc.client.Fault:
|
|
44
|
-
# Sometimes the free public server start page is not available
|
|
45
|
-
# Use a specif instance (this may be very mutable)
|
|
46
|
-
info = {'host': 'https://demo4.odoo.com',
|
|
47
|
-
'database': 'demo_160_1676157153',
|
|
48
|
-
'user': 'admin',
|
|
49
|
-
'password': 'admin'}
|
|
50
|
-
cls.model = Model(model_name='res.partner',
|
|
51
|
-
endpoint=info['host'],
|
|
52
|
-
database=info['database'],
|
|
53
|
-
username=info['user'],
|
|
54
|
-
password=info['password'],
|
|
55
|
-
language='en_US',
|
|
56
|
-
authenticate=False)
|
|
41
|
+
cls.model = utility.get_model_from_demo(model_name='res.partner')
|
|
57
42
|
|
|
58
43
|
def test_01_authenticate(self) -> None:
|
|
59
44
|
"""
|
|
@@ -117,7 +102,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
117
102
|
"""
|
|
118
103
|
Search some rows using filters
|
|
119
104
|
"""
|
|
120
|
-
# Filters by
|
|
105
|
+
# Filters by active and exclude an explicit name
|
|
121
106
|
filters = [BooleanOperator.AND,
|
|
122
107
|
Filter(field='active',
|
|
123
108
|
compare_type=CompareType.EQUAL,
|
|
@@ -231,7 +216,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
231
216
|
"""
|
|
232
217
|
Find multiple rows using some filters
|
|
233
218
|
"""
|
|
234
|
-
# Filters by
|
|
219
|
+
# Filters by active and exclude an explicit name
|
|
235
220
|
filters = [BooleanOperator.AND,
|
|
236
221
|
Filter(field='active',
|
|
237
222
|
compare_type=CompareType.EQUAL,
|
|
@@ -252,7 +237,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
252
237
|
"""
|
|
253
238
|
Find multiple rows using some filters and order
|
|
254
239
|
"""
|
|
255
|
-
# Filters by
|
|
240
|
+
# Filters by active and exclude an explicit name
|
|
256
241
|
filters = [BooleanOperator.AND,
|
|
257
242
|
Filter(field='active',
|
|
258
243
|
compare_type=CompareType.EQUAL,
|
|
@@ -270,7 +255,48 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
270
255
|
# Check if the results list is not empty
|
|
271
256
|
self.assertGreater(len(results), 0)
|
|
272
257
|
|
|
273
|
-
def
|
|
258
|
+
def test_14_first(self) -> None:
|
|
259
|
+
"""
|
|
260
|
+
Find a single row using some filters
|
|
261
|
+
"""
|
|
262
|
+
# Filters by active and exclude an explicit name
|
|
263
|
+
filters = [BooleanOperator.AND,
|
|
264
|
+
Filter(field='active',
|
|
265
|
+
compare_type=CompareType.EQUAL,
|
|
266
|
+
value=False),
|
|
267
|
+
BooleanOperator.NOT,
|
|
268
|
+
Filter(field='name',
|
|
269
|
+
compare_type=CompareType.CONTAINS,
|
|
270
|
+
value='OdooBot'),
|
|
271
|
+
]
|
|
272
|
+
results = self.model.first(filters=filters,
|
|
273
|
+
fields=('id', 'name', 'type', 'street'))
|
|
274
|
+
# Check if the results type is None or dict
|
|
275
|
+
self.assertIn(type(results), (None, dict))
|
|
276
|
+
# Check if the results contains 4 values, for the 4 fields
|
|
277
|
+
self.assertEqual(len(results), 4)
|
|
278
|
+
|
|
279
|
+
def test_15_first_none(self) -> None:
|
|
280
|
+
"""
|
|
281
|
+
Find a single row which returns None
|
|
282
|
+
"""
|
|
283
|
+
# Filters by active and exclude an explicit name
|
|
284
|
+
filters = [BooleanOperator.AND,
|
|
285
|
+
Filter(field='active',
|
|
286
|
+
compare_type=CompareType.EQUAL,
|
|
287
|
+
value=False),
|
|
288
|
+
BooleanOperator.NOT,
|
|
289
|
+
Filter(field='active',
|
|
290
|
+
compare_type=CompareType.EQUAL,
|
|
291
|
+
value=True),
|
|
292
|
+
]
|
|
293
|
+
results = self.model.first(filters=filters,
|
|
294
|
+
fields=('id', 'name', 'type', 'street'),
|
|
295
|
+
offset=1000)
|
|
296
|
+
# Check if the results type is None
|
|
297
|
+
self.assertEqual(results, None)
|
|
298
|
+
|
|
299
|
+
def test_16_get(self) -> None:
|
|
274
300
|
"""
|
|
275
301
|
Get a single row using ID
|
|
276
302
|
"""
|
|
@@ -290,7 +316,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
290
316
|
self.assertEqual(results['type'], 'contact')
|
|
291
317
|
self.assertGreater(len(results['street']), 0)
|
|
292
318
|
|
|
293
|
-
def
|
|
319
|
+
def test_17_get_many(self) -> None:
|
|
294
320
|
"""
|
|
295
321
|
Get multiple rows using ID
|
|
296
322
|
"""
|
|
@@ -308,7 +334,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
308
334
|
self.assertEqual(results[0]['type'], 'contact')
|
|
309
335
|
self.assertGreater(len(results[0]['street']), 0)
|
|
310
336
|
|
|
311
|
-
def
|
|
337
|
+
def test_18_create(self) -> None:
|
|
312
338
|
"""
|
|
313
339
|
Create a new row
|
|
314
340
|
"""
|
|
@@ -319,7 +345,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
319
345
|
# Check if the results is not empty
|
|
320
346
|
self.assertGreater(results, 0)
|
|
321
347
|
|
|
322
|
-
def
|
|
348
|
+
def test_19_many_to_many_add(self) -> None:
|
|
323
349
|
"""
|
|
324
350
|
Add a record to a Many-to-Many relationship
|
|
325
351
|
"""
|
|
@@ -340,7 +366,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
340
366
|
# Check if we have results
|
|
341
367
|
self.assertTrue(results)
|
|
342
368
|
|
|
343
|
-
def
|
|
369
|
+
def test_20_many_to_many_create(self) -> None:
|
|
344
370
|
"""
|
|
345
371
|
Create a new record and add it to a Many-to-Many relationship
|
|
346
372
|
"""
|
|
@@ -358,7 +384,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
358
384
|
# Check if we have results
|
|
359
385
|
self.assertTrue(results)
|
|
360
386
|
|
|
361
|
-
def
|
|
387
|
+
def test_21_many_to_many_update(self) -> None:
|
|
362
388
|
"""
|
|
363
389
|
Update an existing record from a Many-to-Many relationship
|
|
364
390
|
"""
|
|
@@ -390,7 +416,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
390
416
|
# Check if we have results
|
|
391
417
|
self.assertTrue(results)
|
|
392
418
|
|
|
393
|
-
def
|
|
419
|
+
def test_22_many_to_many_delete(self) -> None:
|
|
394
420
|
"""
|
|
395
421
|
Delete an existing child record from a Many-to-Many relationship
|
|
396
422
|
and delete the record itself
|
|
@@ -430,7 +456,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
430
456
|
# We catched a different error, re-raise it
|
|
431
457
|
raise error
|
|
432
458
|
|
|
433
|
-
def
|
|
459
|
+
def test_23_many_to_many_remove(self) -> None:
|
|
434
460
|
"""
|
|
435
461
|
Remove an existing child record from a Many-to-Many relationship
|
|
436
462
|
"""
|
|
@@ -460,7 +486,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
460
486
|
# Check if we have results
|
|
461
487
|
self.assertTrue(results)
|
|
462
488
|
|
|
463
|
-
def
|
|
489
|
+
def test_24_many_to_many_clear(self) -> None:
|
|
464
490
|
"""
|
|
465
491
|
Clear any existing children records from a Many-to-Many relationship
|
|
466
492
|
"""
|
|
@@ -476,7 +502,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
476
502
|
# Check if we have results
|
|
477
503
|
self.assertTrue(results)
|
|
478
504
|
|
|
479
|
-
def
|
|
505
|
+
def test_25_many_to_many_replace(self) -> None:
|
|
480
506
|
"""
|
|
481
507
|
Replace any existing children records from a Many-to-Many relationship
|
|
482
508
|
"""
|
|
@@ -503,7 +529,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
503
529
|
# Check if we have results
|
|
504
530
|
self.assertTrue(results)
|
|
505
531
|
|
|
506
|
-
def
|
|
532
|
+
def test_26_update(self) -> None:
|
|
507
533
|
"""
|
|
508
534
|
Update the newly created rows
|
|
509
535
|
"""
|
|
@@ -532,7 +558,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
532
558
|
# Check the field street
|
|
533
559
|
self.assertEqual(results_updated['street'], 'TEST TEST TEST')
|
|
534
560
|
|
|
535
|
-
def
|
|
561
|
+
def test_27_update_many(self) -> None:
|
|
536
562
|
"""
|
|
537
563
|
Update all the newly created rows at once
|
|
538
564
|
"""
|
|
@@ -547,7 +573,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
547
573
|
self.model.update(entity_id=results,
|
|
548
574
|
values={'street': 'TEST TEST TEST 2'})
|
|
549
575
|
|
|
550
|
-
def
|
|
576
|
+
def test_28_count(self) -> None:
|
|
551
577
|
"""
|
|
552
578
|
Count the newly created rows.
|
|
553
579
|
"""
|
|
@@ -559,7 +585,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
559
585
|
self.assertIsNotNone(results)
|
|
560
586
|
self.assertGreater(results, 0)
|
|
561
587
|
|
|
562
|
-
def
|
|
588
|
+
def test_29_get_model_data_reference(self) -> None:
|
|
563
589
|
"""
|
|
564
590
|
Get a reference row from ir.model.data
|
|
565
591
|
"""
|
|
@@ -571,7 +597,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
571
597
|
self.assertIsInstance(results, dict)
|
|
572
598
|
self.assertGreater(results['res_id'], 0)
|
|
573
599
|
|
|
574
|
-
def
|
|
600
|
+
def test_30_get_message_subtype_id_activity(self) -> None:
|
|
575
601
|
"""
|
|
576
602
|
Get a Message subtype ID
|
|
577
603
|
"""
|
|
@@ -582,7 +608,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
582
608
|
self.assertIsInstance(results, int)
|
|
583
609
|
self.assertGreater(results, 0)
|
|
584
610
|
|
|
585
|
-
def
|
|
611
|
+
def test_31_get_message_subtype_id_comment(self) -> None:
|
|
586
612
|
"""
|
|
587
613
|
Get a Message subtype ID
|
|
588
614
|
"""
|
|
@@ -593,7 +619,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
593
619
|
self.assertIsInstance(results, int)
|
|
594
620
|
self.assertGreater(results, 0)
|
|
595
621
|
|
|
596
|
-
def
|
|
622
|
+
def test_32_get_message_subtype_id_note(self) -> None:
|
|
597
623
|
"""
|
|
598
624
|
Get a Message subtype ID
|
|
599
625
|
"""
|
|
@@ -604,7 +630,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
604
630
|
self.assertIsInstance(results, int)
|
|
605
631
|
self.assertGreater(results, 0)
|
|
606
632
|
|
|
607
|
-
def
|
|
633
|
+
def test_33_post_message_activity(self) -> None:
|
|
608
634
|
"""
|
|
609
635
|
Post a new message as activity
|
|
610
636
|
"""
|
|
@@ -623,7 +649,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
623
649
|
self.assertIsNotNone(entity_id)
|
|
624
650
|
self.assertGreater(entity_id, 0)
|
|
625
651
|
|
|
626
|
-
def
|
|
652
|
+
def test_34_post_message_comment(self) -> None:
|
|
627
653
|
"""
|
|
628
654
|
Post a new message as comment
|
|
629
655
|
"""
|
|
@@ -642,7 +668,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
642
668
|
self.assertIsNotNone(entity_id)
|
|
643
669
|
self.assertGreater(entity_id, 0)
|
|
644
670
|
|
|
645
|
-
def
|
|
671
|
+
def test_35_post_message_note(self) -> None:
|
|
646
672
|
"""
|
|
647
673
|
Post a new message as note
|
|
648
674
|
"""
|
|
@@ -661,7 +687,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
661
687
|
self.assertIsNotNone(entity_id)
|
|
662
688
|
self.assertGreater(entity_id, 0)
|
|
663
689
|
|
|
664
|
-
def
|
|
690
|
+
def test_36_delete(self) -> None:
|
|
665
691
|
"""
|
|
666
692
|
Delete the newly created rows.
|
|
667
693
|
This test may be skipped in the case there's an active PoS session
|
|
@@ -694,7 +720,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
694
720
|
# We catched a different error, re-raise it
|
|
695
721
|
raise error
|
|
696
722
|
|
|
697
|
-
def
|
|
723
|
+
def test_37_delete_many(self) -> None:
|
|
698
724
|
"""
|
|
699
725
|
Delete the newly created rows.
|
|
700
726
|
This test may be skipped in the case there's an active PoS session
|
|
@@ -720,7 +746,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
720
746
|
# We catched a different error, re-raise it
|
|
721
747
|
raise error
|
|
722
748
|
|
|
723
|
-
def
|
|
749
|
+
def test_38_language(self) -> None:
|
|
724
750
|
"""
|
|
725
751
|
Get the current default language, change and restore it
|
|
726
752
|
"""
|
|
@@ -737,7 +763,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
737
763
|
results = self.model.language
|
|
738
764
|
self.assertEqual(results, original_language)
|
|
739
765
|
|
|
740
|
-
def
|
|
766
|
+
def test_39_get_fields(self) -> None:
|
|
741
767
|
"""
|
|
742
768
|
Get the model fields
|
|
743
769
|
"""
|
|
@@ -745,7 +771,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
745
771
|
# Check if we have results
|
|
746
772
|
self.assertIsNotNone(results)
|
|
747
773
|
|
|
748
|
-
def
|
|
774
|
+
def test_40_get_fields_attributes(self) -> None:
|
|
749
775
|
"""
|
|
750
776
|
Get the model fields
|
|
751
777
|
"""
|
|
@@ -758,7 +784,7 @@ class TestCaseContacts(unittest.TestCase):
|
|
|
758
784
|
self.assertIn('string', field_name)
|
|
759
785
|
self.assertIn('type', field_name)
|
|
760
786
|
|
|
761
|
-
def
|
|
787
|
+
def test_41_get_model(self) -> None:
|
|
762
788
|
"""
|
|
763
789
|
Get a new Model object
|
|
764
790
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|