Merge lp:~jfb-tempo-consulting/unifield-server/US-8366 into lp:unifield-server

Proposed by jftempo
Status: Merged
Merged at revision: 5975
Proposed branch: lp:~jfb-tempo-consulting/unifield-server/US-8366
Merge into: lp:unifield-server
Diff against target: 635 lines (+207/-34) (has conflicts)
14 files modified
bin/addons/msf_doc_import/purchase_order.py (+24/-8)
bin/addons/msf_profile/data/patches.xml (+8/-0)
bin/addons/msf_profile/msf_profile.py (+23/-0)
bin/addons/msf_tools/automated_export.py (+22/-6)
bin/addons/msf_tools/automated_export_data.xml (+1/-0)
bin/addons/msf_tools/automated_export_function.py (+2/-0)
bin/addons/msf_tools/automated_import.py (+75/-8)
bin/addons/msf_tools/automated_import_data.xml (+5/-1)
bin/addons/msf_tools/automated_import_function.py (+2/-0)
bin/addons/msf_tools/automated_import_job.py (+10/-5)
bin/addons/msf_tools/views/automated_export_view.xml (+16/-2)
bin/addons/msf_tools/views/automated_import_view.xml (+15/-3)
bin/osv/orm.py (+3/-1)
bin/unifield-version.txt (+1/-0)
Text conflict in bin/addons/msf_profile/data/patches.xml
To merge this branch: bzr merge lp:~jfb-tempo-consulting/unifield-server/US-8366
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+402432@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/addons/msf_doc_import/purchase_order.py'
2--- bin/addons/msf_doc_import/purchase_order.py 2020-12-14 16:49:10 +0000
3+++ bin/addons/msf_doc_import/purchase_order.py 2021-05-07 16:00:52 +0000
4@@ -65,12 +65,12 @@
5 return result
6
7 def export_po(self, cr, uid, ids, context=None):
8- auto_job_ids = self.pool.get('automated.export').search(cr, uid, [('function_id.method_to_call', '=', 'auto_export_validated_purchase_order'), ('active', '=', True)], context=context)
9+ wiz = self.browse(cr, uid, ids[0], context)
10+ auto_job_ids = self.pool.get('automated.export').search(cr, uid, [('function_id.method_to_call', '=', 'auto_export_validated_purchase_order'), ('active', '=', True), ('partner_id', '=', wiz.purchase_id.partner_id.id)], context=context)
11 if not auto_job_ids:
12 raise osv.except_osv(_('Warning'), _('The job to export PO is not active.'))
13
14 auto_job = self.pool.get('automated.export').browse(cr, uid, auto_job_ids[0], context=context)
15- wiz = self.browse(cr, uid, ids[0], context)
16
17
18 processed, rejected, trash = self.pool.get('purchase.order').auto_export_validated_purchase_order(cr, uid, auto_job, [wiz.purchase_id.id], context=context)
19@@ -126,11 +126,26 @@
20 for id in ids:
21 ret[id] = False
22
23- if not self.pool.get('automated.export').search_exist(cr, uid, [('function_id.method_to_call', '=', 'auto_export_validated_purchase_order'), ('active', '=', True)], context=context):
24- return ret
25-
26- for x in self.search(cr, uid, [('id', 'in', ids), ('partner_type', '=', 'esc'), ('state', 'in', ['validated', 'validated_p'])], context=context):
27- ret[x] = True
28+ if not ids:
29+ return {}
30+
31+ cr.execute('''
32+ select o.id
33+ from
34+ purchase_order o, automated_export exp, automated_export_function fnct
35+ where
36+ o.id in %s and
37+ o.partner_type = 'esc' and
38+ o.state in ('validated', 'validated_p') and
39+ o.partner_id = exp.partner_id and
40+ exp.active = 't' and
41+ exp.function_id = fnct.id and
42+ fnct.method_to_call = 'auto_export_validated_purchase_order'
43+ ''', (tuple(ids), ))
44+
45+ for x in cr.fetchall():
46+ ret[x[0]] = True
47+
48 return ret
49
50 _columns = {
51@@ -390,7 +405,8 @@
52 ('partner_type', '=', 'esc'),
53 ('state', 'in', ['validated', 'validated_p']),
54 ('auto_exported_ok', '=', False),
55- ], context= context)
56+ ('partner_id', '=', export_wiz.partner_id.id),
57+ ], context=context)
58
59 if not po_ids:
60 msg = _('No PO to export !')
61
62=== modified file 'bin/addons/msf_profile/data/patches.xml'
63--- bin/addons/msf_profile/data/patches.xml 2021-02-25 15:48:01 +0000
64+++ bin/addons/msf_profile/data/patches.xml 2021-05-07 16:00:52 +0000
65@@ -647,9 +647,17 @@
66 <field name="method">us_6796_hide_prod_status_inconsistencies</field>
67 </record>
68
69+<<<<<<< TREE
70 <record id="us_8166_hide_consolidated_sm_report" model="patch.scripts">
71 <field name="method">us_8166_hide_consolidated_sm_report</field>
72 </record>
73
74+=======
75+ <!-- UF21.0 -->
76+ <record id="us_7941_auto_vi_set_partner" model="patch.scripts">
77+ <field name="method">us_7941_auto_vi_set_partner</field>
78+ </record>
79+
80+>>>>>>> MERGE-SOURCE
81 </data>
82 </openerp>
83
84=== modified file 'bin/addons/msf_profile/msf_profile.py'
85--- bin/addons/msf_profile/msf_profile.py 2021-05-05 07:42:20 +0000
86+++ bin/addons/msf_profile/msf_profile.py 2021-05-07 16:00:52 +0000
87@@ -51,6 +51,29 @@
88 _defaults = {
89 'model': lambda *a: 'patch.scripts',
90 }
91+ # UF21.0
92+ def us_7941_auto_vi_set_partner(self, cr, uid, *a, **b):
93+ cr.execute('''
94+ update automated_import imp set partner_id = (select id from res_partner where ref='APU' and partner_type='esc' LIMIT 1)
95+ from automated_import_function function
96+ where
97+ function.id = imp.function_id and
98+ imp.partner_id is null and
99+ function.multiple='t'
100+ ''')
101+ self._logger.warn('APU set on %s VI import.' % (cr.rowcount,))
102+
103+ cr.execute('''
104+ update automated_export exp set partner_id = (select id from res_partner where ref='APU' and partner_type='esc' LIMIT 1)
105+ from automated_export_function function
106+ where
107+ function.id = exp.function_id and
108+ exp.partner_id is null and
109+ function.multiple='t'
110+ ''')
111+ self._logger.warn('APU set on %s VI export.' % (cr.rowcount,))
112+
113+ return True
114
115 # UF21.0
116 def us_8166_hide_consolidated_sm_report(self, cr, uid, *a, **b):
117
118=== modified file 'bin/addons/msf_tools/automated_export.py'
119--- bin/addons/msf_tools/automated_export.py 2021-04-16 14:59:16 +0000
120+++ bin/addons/msf_tools/automated_export.py 2021-05-07 16:00:52 +0000
121@@ -33,6 +33,16 @@
122
123 class automated_export(osv.osv):
124 _name = 'automated.export'
125+ _order = 'name, id'
126+
127+ def _auto_init(self, cr, context=None):
128+ res = super(automated_export, self)._auto_init(cr, context)
129+ # migration delete old constraint
130+ cr.drop_constraint_if_exists('automated_export', 'automated_export_export_function_id_uniq')
131+ cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'automated_export_function_id_partner_id_uniq'")
132+ if not cr.fetchone():
133+ cr.execute("CREATE UNIQUE INDEX automated_export_function_id_partner_id_uniq ON automated_export (function_id, coalesce(partner_id, 0))")
134+ return res
135
136 _columns = {
137 'name': fields.char(
138@@ -77,6 +87,7 @@
139 required=True,
140 ),
141 'disable_cron': fields.related('function_id', 'disable_cron', string='Cron disabled', type='boolean', write_relate=False),
142+ 'multiple': fields.related('function_id', 'multiple', string='Multiple', type='boolean', write_relate=False),
143 'export_format': fields.selection(
144 selection=[
145 ('excel', 'Excel'),
146@@ -109,6 +120,7 @@
147 'ftp_dest_ok': fields.boolean(string='on FTP server', help='Is given path is located on FTP server ?'),
148 'ftp_dest_fail_ok': fields.boolean(string='on FTP server', help='Is given path is located on FTP server ?'),
149 'ftp_report_ok': fields.boolean(string='on FTP server', help='Is given path is located on FTP server ?'),
150+ 'partner_id': fields.many2one('res.partner', 'Partner', domain=[('supplier', '=', True), ('partner_type', '=', 'esc')]),
151 'pause': fields.integer('Pause between generation and transfer (in seconds)'),
152
153 }
154@@ -129,10 +141,11 @@
155 _('Another Automated export with same name already exists (maybe inactive). Automated export name must be unique. Please select an other name.'),
156 ),
157 (
158- 'export_function_id_uniq',
159- 'unique(function_id)',
160- _('Another Automated export with same functionality already exists (maybe inactive). Only one automated export must be created for a '\
161- 'same functionality. Please select an other functionality.'),
162+ # declared in _auto_init
163+ 'function_id_partner_id_uniq',
164+ '',
165+ _('Another Automated export with same functionality and same partner already exists (maybe inactive). Only one automated export must be created for a '\
166+ 'same functionality and partner.'),
167 ),
168 (
169 'export_positive_interval',
170@@ -143,9 +156,12 @@
171
172 def change_function_id(self, cr, uid, ids, function_id, context=None):
173 disable_cron = False
174+ multiple = False
175 if function_id:
176- disable_cron = self.pool.get('automated.export.function').browse(cr, uid, function_id, context=context).disable_cron
177- return {'value': {'disable_cron': disable_cron}}
178+ fct_data = self.pool.get('automated.export.function').browse(cr, uid, function_id, context=context)
179+ disable_cron = fct_data.disable_cron
180+ multiple = fct_data.multiple
181+ return {'value': {'disable_cron': disable_cron, 'multiple': multiple}}
182
183 def onchange_ftp_ok(self, cr, uid, ids, ftp_ok, context=None):
184 if context is None:
185
186=== modified file 'bin/addons/msf_tools/automated_export_data.xml'
187--- bin/addons/msf_tools/automated_export_data.xml 2020-09-18 10:39:31 +0000
188+++ bin/addons/msf_tools/automated_export_data.xml 2021-05-07 16:00:52 +0000
189@@ -5,6 +5,7 @@
190 <field name="name">Export validated Purchase Order</field>
191 <field name="model_id" model="ir.model" search="[('model', '=', 'purchase.order')]" />
192 <field name="method_to_call">auto_export_validated_purchase_order</field>
193+ <field name="multiple" eval="True" />
194 </record>
195 <record id="auto_export_fnct_oca_finance_vi" model="automated.export.function">
196 <field name="name">Export to HQ system (OCA) - Not yet exported</field>
197
198=== modified file 'bin/addons/msf_tools/automated_export_function.py'
199--- bin/addons/msf_tools/automated_export_function.py 2020-09-18 10:39:31 +0000
200+++ bin/addons/msf_tools/automated_export_function.py 2021-05-07 16:00:52 +0000
201@@ -45,11 +45,13 @@
202 required=True,
203 ),
204 'disable_cron': fields.boolean('No cron'),
205+ 'multiple': fields.boolean('Allow multiple jobs'),
206 }
207
208 _defaults = {
209 'method_to_call': lambda *a: 'export_data_from_csv',
210 'disable_cron': False,
211+ 'multiple': False,
212 }
213
214 _order = 'name'
215
216=== modified file 'bin/addons/msf_tools/automated_import.py'
217--- bin/addons/msf_tools/automated_import.py 2020-10-20 12:50:50 +0000
218+++ bin/addons/msf_tools/automated_import.py 2021-05-07 16:00:52 +0000
219@@ -33,6 +33,16 @@
220
221 class automated_import(osv.osv):
222 _name = 'automated.import'
223+ _order = 'name, id'
224+
225+ def _auto_init(self, cr, context=None):
226+ res = super(automated_import, self)._auto_init(cr, context)
227+ # migration delete old constraint
228+ cr.drop_constraint_if_exists('automated_import', 'automated_import_import_function_id_uniq')
229+ cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'automated_import_function_id_partner_id_uniq'")
230+ if not cr.fetchone():
231+ cr.execute("CREATE UNIQUE INDEX automated_import_function_id_partner_id_uniq ON automated_import (function_id, coalesce(partner_id, 0))")
232+ return res
233
234 def _check_paths(self, cr, uid, ids, context=None):
235 """
236@@ -73,6 +83,44 @@
237
238 return True
239
240+ def _check_unicity(self, cr, uid, ids, context=None):
241+ '''
242+ if the function_id allows multiple then the server / src_path must be unique
243+ if not multiple: then function_id must be unique
244+ '''
245+
246+ error = []
247+ cr.execute('''
248+ select function.name
249+ from automated_import import, automated_import_function function
250+ where
251+ function.id = import.function_id and
252+ coalesce(function.multiple, 'f') = 'f'
253+ group by function.name
254+ having(count(*) > 1)
255+ ''')
256+ for x in cr.fetchall():
257+ error.append(_('Another Automated import with same functionality "%s" already exists (maybe inactive). Only one automated import must be created for a '\
258+ 'same functionality. Please select an other functionality.') % x[0])
259+
260+ cr.execute('''
261+ select function.name
262+ from automated_import import, automated_import_function function
263+ where
264+ function.id = import.function_id and
265+ coalesce(function.multiple, 'f') = 't' and
266+ coalesce(src_path, '') != ''
267+ group by function.name, src_path, ftp_url
268+ having(count(*) > 1)
269+ ''')
270+ for x in cr.fetchall():
271+ error.append(_('Another Automated import with same functionality "%s", same server and same source already exists (maybe inactive).') % x[0])
272+
273+ if error:
274+ raise osv.except_osv(_('Warning'), "\n".join(error))
275+
276+ return True
277+
278 def _get_isadmin(self, cr, uid, ids, *a, **b):
279 ret = {}
280 for _id in ids:
281@@ -123,6 +171,7 @@
282 string='Functionality',
283 required=True,
284 ),
285+ 'multiple': fields.related('function_id', 'multiple', string='Multiple', type='boolean', write_relate=False),
286 'active': fields.boolean(
287 string='Active',
288 readonly=True,
289@@ -149,6 +198,7 @@
290 'ftp_dest_fail_ok': fields.boolean(string='on FTP server', help='Is given path is located on FTP server ?'),
291 'ftp_report_ok': fields.boolean(string='on FTP server', help='Is given path is located on FTP server ?'),
292 'is_admin': fields.function(_get_isadmin, method=True, type='boolean', string='Is Admin'),
293+ 'partner_id': fields.many2one('res.partner', 'Partner', domain=[('partner_type', '=', 'esc')]),
294 }
295
296 _defaults = {
297@@ -167,10 +217,9 @@
298 _('Another Automated import with same name already exists (maybe inactive). Automated import name must be unique. Please select an other name.'),
299 ),
300 (
301- 'import_function_id_uniq',
302- 'unique(function_id)',
303- _('Another Automated import with same functionality already exists (maybe inactive). Only one automated import must be created for a '\
304- 'same functionality. Please select an other functionality.'),
305+ 'function_id_partner_id_uniq',
306+ '',
307+ _('Another Automated import with same function / same partner already exists (maybe inactive).'),
308 ),
309 (
310 'import_positive_interval',
311@@ -181,8 +230,20 @@
312
313 _constraints = [
314 (_check_paths, _('There is a problem with paths'), ['active', 'src_path', 'dest_path', 'report_path', 'dest_path_failure']),
315+ (_check_unicity, _('There is a problem with paths'), []),
316 ]
317
318+ def change_function_id(self, cr, uid, ids, function_id, context=None):
319+ multiple = False
320+ value = {}
321+ if function_id:
322+ fct_data = self.pool.get('automated.import.function').browse(cr, uid, function_id, context=context)
323+ multiple = fct_data.multiple
324+ if not multiple:
325+ value['partner_id'] = False
326+ value['multiple'] = multiple
327+ return {'value': value}
328+
329 def onchange_ftp_ok(self, cr, uid, ids, ftp_ok, context=None):
330 if context is None:
331 context = {}
332@@ -290,14 +351,20 @@
333
334 main_path = os.path.join(config.get('root_path'), 'vi_auto_import')
335 write_me = {'ftp_source_ok': False, 'ftp_dest_ok': False, 'ftp_dest_fail_ok': False, 'ftp_report_ok': False, 'ftp_ok': False, 'active': True, 'interval_unit': 'months', 'interval': 12}
336+
337+ prefix = ''
338+ for job in self.browse(cr, uid, ids, fields_to_fetch=['name', 'function_id'], context=context):
339+ if job.function_id.multiple:
340+ num = self.search(cr, uid, [('function_id', '=', job.function_id.id), ('active', 'in', ['t', 'f'])], count=True, context=context)
341+ if num > 1:
342+ prefix = num
343+ self.log(cr, uid, job.id, 'Auto configuration done on job %s' % job.name)
344+
345 for directory in ['src_path', 'dest_path', 'dest_path_failure', 'report_path']:
346- target = os.path.join(main_path, directory)
347+ target = os.path.join(main_path, '%s%s' % (directory, prefix))
348 write_me[directory] = target
349 if not os.path.exists(target):
350 os.makedirs(target)
351-
352- for job in self.read(cr, uid, ids, ['name'], context=context):
353- self.log(cr, uid, job['id'], 'Auto configuration done on job %s' % job['name'])
354 self.write(cr, uid, ids, write_me, context=context)
355 return True
356
357
358=== modified file 'bin/addons/msf_tools/automated_import_data.xml'
359--- bin/addons/msf_tools/automated_import_data.xml 2018-03-29 07:34:43 +0000
360+++ bin/addons/msf_tools/automated_import_data.xml 2021-05-07 16:00:52 +0000
361@@ -61,6 +61,7 @@
362 <field name="model_id" model="ir.model" search="[('model', '=', 'supplier.catalogue')]" />
363 <field name="method_to_call">auto_import</field>
364 <field name="startswith">SCL_</field>
365+ <field name="multiple" eval="True" />
366 </record>
367
368 <record id="auto_import_fnct_product_list" model="automated.import.function">
369@@ -75,6 +76,7 @@
370 <field name="model_id" model="ir.model" search="[('model', '=', 'stock.picking')]" />
371 <field name="method_to_call">auto_import_incoming_shipment</field>
372 <field name="startswith">SHPM_</field>
373+ <field name="multiple" eval="True" />
374 </record>
375
376 <record id="auto_import_fnct_purchase_order" model="automated.import.function">
377@@ -82,13 +84,15 @@
378 <field name="model_id" model="ir.model" search="[('model', '=', 'purchase.order')]" />
379 <field name="method_to_call">auto_import_purchase_order</field>
380 <field name="startswith">POV_</field>
381+ <field name="multiple" eval="True" />
382 </record>
383-
384+
385 <record id="auto_import_fnct_confirmed_purchase_order" model="automated.import.function">
386 <field name="name">Import Purchase Order and confirm</field>
387 <field name="model_id" model="ir.model" search="[('model', '=', 'purchase.order')]" />
388 <field name="method_to_call">auto_import_confirmed_purchase_order</field>
389 <field name="startswith">POV_</field>
390+ <field name="multiple" eval="True" />
391 </record>
392
393 <record id="auto_import_fnct_product_categories" model="automated.import.function">
394
395=== modified file 'bin/addons/msf_tools/automated_import_function.py'
396--- bin/addons/msf_tools/automated_import_function.py 2018-03-29 07:34:43 +0000
397+++ bin/addons/msf_tools/automated_import_function.py 2021-05-07 16:00:52 +0000
398@@ -45,10 +45,12 @@
399 required=True,
400 ),
401 'startswith': fields.char('Starts with', size=56),
402+ 'multiple': fields.boolean('Allow multiple jobs'),
403 }
404
405 _defaults = {
406 'method_to_call': lambda *a: 'import_data_from_csv',
407+ 'multiple': False,
408 }
409
410 _order = 'name'
411
412=== modified file 'bin/addons/msf_tools/automated_import_job.py'
413--- bin/addons/msf_tools/automated_import_job.py 2020-10-20 15:14:32 +0000
414+++ bin/addons/msf_tools/automated_import_job.py 2021-05-07 16:00:52 +0000
415@@ -41,6 +41,7 @@
416 from mission_stock.mission_stock import UnicodeWriter
417
418 from threading import RLock
419+import re
420
421 def all_files_under(path, startswith=False, already=None):
422 """
423@@ -78,12 +79,17 @@
424 ftp_connec.retrlines('RETR %s' % file, add_line)
425 return ch.getvalue()
426 elif sftp:
427- tmp_file_path = os.path.join(tempfile.gettempdir(), os.path.basename(file))
428+ tmp_file_path = os.path.join(tempfile.gettempdir(), remove_special_chars(os.path.basename(file)))
429 sftp.get(file, tmp_file_path)
430 with open(tmp_file_path, 'r') as fich:
431 return fich.read()
432 return False
433
434+def remove_special_chars(filename):
435+ if os.name == 'nt' and filename:
436+ return re.sub(r'[\\/:*?"<>|]', '_', filename)
437+
438+ return filename
439
440 def move_to_process_path(import_brw, ftp_connec, sftp, file, success):
441 """
442@@ -99,7 +105,7 @@
443 if dest_on_ftp:
444 destname = posixpath.join(import_brw.dest_path if success else import_brw.dest_path_failure, '%s_%s' % (time.strftime('%Y%m%d_%H%M%S'), file))
445 else:
446- destname = os.path.join(import_brw.dest_path if success else import_brw.dest_path_failure, '%s_%s' % (time.strftime('%Y%m%d_%H%M%S'), file))
447+ destname = os.path.join(import_brw.dest_path if success else import_brw.dest_path_failure, '%s_%s' % (time.strftime('%Y%m%d_%H%M%S'), remove_special_chars(file)))
448
449 logging.getLogger('automated.import').info(_('Moving %s to %s') % (srcname, destname))
450
451@@ -431,7 +437,6 @@
452 import_obj.path_is_accessible(import_data[path[0]], path[1])
453 except osv.except_osv as e:
454 error = tools.ustr(e)
455- no_file = True
456 # In case of manual processing, raise the error
457 if job.file_to_import:
458 raise e
459@@ -453,7 +458,6 @@
460 except ValueError:
461 no_file = True
462 except Exception as e:
463- no_file = True
464 error = tools.ustr(traceback.format_exc())
465
466 if not error:
467@@ -484,6 +488,7 @@
468 'file_sum': md5,
469 'state': 'done' if no_file else 'error',
470 }, context=context)
471+ no_file = True
472 continue
473 else: # file to import given
474 no_file = True
475@@ -509,7 +514,7 @@
476 temp_file.close()
477 oldest_file = temp_file.name
478 elif import_data.ftp_source_ok and import_data.ftp_protocol == 'sftp':
479- tmp_dest_path = os.path.join(tempfile.gettempdir(), filename)
480+ tmp_dest_path = os.path.join(tempfile.gettempdir(), remove_special_chars(filename))
481 sftp.get(oldest_file, tmp_dest_path)
482 oldest_file = tmp_dest_path
483
484
485=== modified file 'bin/addons/msf_tools/views/automated_export_view.xml'
486--- bin/addons/msf_tools/views/automated_export_view.xml 2021-04-16 14:59:16 +0000
487+++ bin/addons/msf_tools/views/automated_export_view.xml 2021-05-07 16:00:52 +0000
488@@ -8,9 +8,16 @@
489 <field name="type">search</field>
490 <field name="arch" type="xml">
491 <search string="Automated exports">
492- <filter name="inactive" domain="[('active', '=', False)]" string="Inactive" icon="gtk-undo" />
493+ <filter icon="terp-check" name="filteractive" string="Active" domain="[('active', '=', True)]" />
494+ <filter icon="gtk-dialog-error" name="filterinactive" string="Inactive" domain="[('active', '=', False)]" />
495 <field name="name" />
496 <field name="function_id" />
497+ <field name="partner_id" />
498+ <newline />
499+ <group expand="1" string="Group By..." colspan="4" col="4">
500+ <filter string="Partner" name="groupby_partner_id" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
501+ <filter string="Function" name="groupby_function_id" icon="terp-accessories-archiver" domain="[]" context="{'group_by':'function_id'}"/>
502+ </group>
503 </search>
504 </field>
505 </record>
506@@ -20,12 +27,14 @@
507 <field name="model">automated.export</field>
508 <field name="type">tree</field>
509 <field name="arch" type="xml">
510- <tree string="Automated exports">
511+ <tree string="Automated exports" colors="red: not active">
512 <field name="name" />
513 <field name="function_id" />
514+ <field name="partner_id" />
515 <field name="start_time" />
516 <field name="interval" />
517 <field name="interval_unit" />
518+ <field name="active" />
519 </tree>
520 </field>
521 </record>
522@@ -41,11 +50,15 @@
523 <field name="function_id" widget="selection" on_change="change_function_id(function_id)"/>
524 <field name="active" />
525 <field name="export_format" attrs="{'invisible': [('disable_cron', '=', True)]}"/>
526+ <label colspan="2" />
527+ <field name="partner_id" attrs="{'invisible': [('multiple', '=', False)], 'required': [('multiple', '=', True)]}"/>
528+ <newline />
529 <field name="pause" attrs="{'invisible': [('disable_cron', '=', False)]}"/>
530 <button name="run_job_manually" string="Run job manually" colspan="2" type="object" icon="gtk-execute" />
531 <button name="sent_to_remote" string="Manually send to FTP" colspan="2" type="object" icon="cloud.png" attrs="{'invisible': ['|', ('disable_cron', '=', False), ('ftp_ok', '=', False)]}" />
532
533 <field name="disable_cron" invisible="1" />
534+ <field name="multiple" invisible="1" />
535
536 <separator colspan="4" string="FTP server" />
537 <group col="4" colspan="4">
538@@ -88,6 +101,7 @@
539 <field name="res_model">automated.export</field>
540 <field name="view_type">form</field>
541 <field name="view_mode">tree,form</field>
542+ <field name="context">{'search_default_filteractive' : 1}</field>
543 </record>
544 <menuitem
545 id="automated_export_menu"
546
547=== modified file 'bin/addons/msf_tools/views/automated_import_view.xml'
548--- bin/addons/msf_tools/views/automated_import_view.xml 2020-10-20 15:14:32 +0000
549+++ bin/addons/msf_tools/views/automated_import_view.xml 2021-05-07 16:00:52 +0000
550@@ -8,9 +8,16 @@
551 <field name="type">search</field>
552 <field name="arch" type="xml">
553 <search string="Automated imports">
554- <filter name="inactive" domain="[('active', '=', False)]" string="Inactive" icon="gtk-undo" />
555+ <filter icon="terp-check" name="filteractive" string="Active" domain="[('active', '=', True)]" />
556+ <filter icon="gtk-dialog-error" name="filterinactive" string="Inactive" domain="[('active', '=', False)]" />
557 <field name="name" />
558 <field name="function_id" />
559+ <field name="partner_id" />
560+ <newline />
561+ <group expand="1" string="Group By..." colspan="4" col="4">
562+ <filter string="Partner" name="groupby_partner_id" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
563+ <filter string="Function" name="groupby_function_id" icon="terp-accessories-archiver" domain="[]" context="{'group_by':'function_id'}"/>
564+ </group>
565 </search>
566 </field>
567 </record>
568@@ -20,12 +27,14 @@
569 <field name="model">automated.import</field>
570 <field name="type">tree</field>
571 <field name="arch" type="xml">
572- <tree string="Automated imports">
573+ <tree string="Automated imports" colors="red: not active">
574 <field name="name" />
575 <field name="function_id" />
576+ <field name="partner_id" />
577 <field name="start_time" />
578 <field name="interval" />
579 <field name="interval_unit" />
580+ <field name="active" />
581 </tree>
582 </field>
583 </record>
584@@ -58,9 +67,11 @@
585 });
586 </script>
587 </html>
588+ <field name="multiple" invisible="1" />
589 <field name="name" />
590- <field name="function_id" widget="selection" />
591+ <field name="function_id" widget="selection" on_change="change_function_id(function_id)" />
592 <field name="active" />
593+ <field name="partner_id" attrs="{'invisible': [('multiple', '=', False)], 'required': [('multiple', '=', True)]}"/>
594 <field name="is_admin" invisible="1"/>
595 <button name="run_job_manually" string="Run job manually" colspan="2" type="object" icon="gtk-execute" />
596 <button name="local_autoconfig" string="Local Auto Configuration" colspan="2" type="object" icon="terp-dialog-close" confirm="This action should only be executed on a Sandbox, it will override the current configuration. Do you confirm ?" attrs="{'invisible': [('is_admin', '=', False)]}"/>
597@@ -108,6 +119,7 @@
598 <field name="res_model">automated.import</field>
599 <field name="view_type">form</field>
600 <field name="view_mode">tree,form</field>
601+ <field name="context">{'search_default_filteractive' : 1}</field>
602 </record>
603 <menuitem
604 id="automated_import_menu"
605
606=== modified file 'bin/osv/orm.py'
607--- bin/osv/orm.py 2021-02-02 10:20:51 +0000
608+++ bin/osv/orm.py 2021-05-07 16:00:52 +0000
609@@ -3425,6 +3425,8 @@
610 cr.commit() # start a new transaction
611
612 for (key, con, null) in self._sql_constraints:
613+ if not con:
614+ continue
615 conname = '%s_%s' % (self._table, key)
616
617 cr.execute("SELECT conname, pg_catalog.pg_get_constraintdef(oid, true) as condef FROM pg_constraint where conname=%s", (conname,))
618@@ -4007,7 +4009,7 @@
619 [('res_id','in',list(sub_ids)),('model','=',self._name)],
620 order='NO_ORDER', context=context)
621
622- if self._name in xmlid_no_delete.prevent_deletion:
623+ if referenced_ids and self._name in xmlid_no_delete.prevent_deletion:
624 cr.execute('''select module, name from ir_model_data
625 where
626 (module, name) in %s and
627
628=== modified file 'bin/unifield-version.txt'
629--- bin/unifield-version.txt 2021-04-30 12:22:42 +0000
630+++ bin/unifield-version.txt 2021-05-07 16:00:52 +0000
631@@ -85,3 +85,4 @@
632 5fe4c98efbdc3f75383ef8861f0809f6 2021-01-18 16:00:00 UF19.1
633 3b85912ea6e4cc65910b7be7ff5598d0 2021-03-15 11:00:00 UF20.0
634 965ee9cddbd999bd8d8201f4f6637ee5 2021-04-30 14:00:00 UF20.1
635+165ee9cddbd999bd8d8201f4f6637ee5 2021-04-30 14:00:00 UF20.1-t

Subscribers

People subscribed via source and target branches