Merge lp:~fabien-morin/unifield-server/fm-us-2619-2661-merged into lp:unifield-server

Proposed by jftempo
Status: Rejected
Rejected by: jftempo
Proposed branch: lp:~fabien-morin/unifield-server/fm-us-2619-2661-merged
Merge into: lp:unifield-server
Diff against target: 2792 lines (+2080/-112)
16 files modified
bin/addons/base/i18n/fr.po (+12/-0)
bin/addons/base/ir/ir_actions.py (+1/-1)
bin/addons/import_data/import_data.py (+4/-1)
bin/addons/msf_doc_import/__init__.py (+1/-0)
bin/addons/msf_doc_import/__openerp__.py (+1/-0)
bin/addons/msf_doc_import/doc_import_report.xml (+11/-0)
bin/addons/msf_doc_import/msf_import_export.py (+792/-0)
bin/addons/msf_doc_import/msf_import_export_conf.py (+530/-0)
bin/addons/msf_doc_import/report/export_generic.mako (+137/-0)
bin/addons/msf_doc_import/report/import_generic_template.mako (+21/-0)
bin/addons/msf_doc_import/report/import_generic_template.py (+52/-0)
bin/addons/msf_doc_import/view/msf_import_export_view.xml (+96/-0)
bin/addons/msf_doc_import/wizard/abstract_wizard_import.py (+16/-3)
bin/addons/msf_profile/i18n/fr_MF.po (+364/-96)
bin/addons/product_nomenclature/product_nomenclature.py (+1/-1)
bin/osv/orm.py (+41/-10)
To merge this branch: bzr merge lp:~fabien-morin/unifield-server/fm-us-2619-2661-merged
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+326749@code.launchpad.net
To post a comment you must log in.
4325. By Fabien MORIN

US-2619-2661 [FIX] do not apply this change in the context of
sync_update_execution as both the import and the update execution uses the same
import_data method.

4326. By Fabien MORIN

US-2619-2661 [MERGE] with latest trunk

Unmerged revisions

4326. By Fabien MORIN

US-2619-2661 [MERGE] with latest trunk

4325. By Fabien MORIN

US-2619-2661 [FIX] do not apply this change in the context of
sync_update_execution as both the import and the update execution uses the same
import_data method.

4324. By Fabien MORIN

US-2619 US-2661 [FIX] do not allow new line charcter in strings at import

4323. By Fabien MORIN

US-2619 US-2661 [MERGE] with 2619 improvments

4322. By Fabien MORIN

US-2619 US-2661 [MERGE] small fix from US-2661

4321. By Fabien MORIN

US-2619 - US-2661 [MERGE] last modification of US-2661

4320. By Fabien MORIN

US-2619 - US-2661 [MERGE] both ticket in a same branch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/addons/base/i18n/fr.po'
2--- bin/addons/base/i18n/fr.po 2016-12-15 16:14:13 +0000
3+++ bin/addons/base/i18n/fr.po 2017-09-12 08:08:04 +0000
4@@ -9695,3 +9695,15 @@
5 #: selection:base.language.install,lang:0
6 msgid "Russian / русский язык"
7 msgstr "Russie / русский язык"
8+
9+#. module: base
10+#: code:addons/orm.py:935
11+#, python-format
12+msgid "New line characters in the field '%s' not allowed. Please fix entry :\n'%s'"
13+msgstr "Le caractère de retour à la ligne dans le champ '%s' est interdit. Veuillez corriger l'entrée:\n'%s'"
14+
15+#. module: base
16+#: code:addons/orm.py:1042
17+#, python-format
18+msgid "Line %s: %s"
19+msgstr "Ligne %s: %s"
20
21=== modified file 'bin/addons/base/ir/ir_actions.py'
22--- bin/addons/base/ir/ir_actions.py 2017-05-18 12:16:12 +0000
23+++ bin/addons/base/ir/ir_actions.py 2017-09-12 08:08:04 +0000
24@@ -150,7 +150,7 @@
25 _name = 'ir.actions.act_window'
26 _table = 'ir_act_window'
27 _sequence = 'ir_actions_id_seq'
28- _order = 'name'
29+ _order = 'name, id'
30 _replace_exported_fields = {
31 'groups_txt': [
32 (['groups_id', 'Groups'], 10)
33
34=== modified file 'bin/addons/import_data/import_data.py'
35--- bin/addons/import_data/import_data.py 2016-05-24 08:44:23 +0000
36+++ bin/addons/import_data/import_data.py 2017-09-12 08:08:04 +0000
37@@ -46,7 +46,10 @@
38
39 if data.get('parent_id', False):
40 n_obj = self.pool.get('product.nomenclature')
41- parent_ids = n_obj.search(cr, uid, [('msfid', '=', data['parent_id'])], limit=1)
42+ if isinstance(data['parent_id'], (int, long)):
43+ parent_ids = [data['parent_id']]
44+ else:
45+ parent_ids = n_obj.search(cr, uid, [('msfid', '=', data['parent_id'])], limit=1)
46 if parent_ids:
47 parent_id = parent_ids[0]
48
49
50=== modified file 'bin/addons/msf_doc_import/__init__.py'
51--- bin/addons/msf_doc_import/__init__.py 2016-05-17 12:05:25 +0000
52+++ bin/addons/msf_doc_import/__init__.py 2017-09-12 08:08:04 +0000
53@@ -54,3 +54,4 @@
54 import product_list
55 import supplier_catalogue
56 import report
57+import msf_import_export
58
59=== modified file 'bin/addons/msf_doc_import/__openerp__.py'
60--- bin/addons/msf_doc_import/__openerp__.py 2017-05-22 16:04:34 +0000
61+++ bin/addons/msf_doc_import/__openerp__.py 2017-09-12 08:08:04 +0000
62@@ -51,6 +51,7 @@
63 'view/stock_picking_import_lines_view.xml',
64 'view/replenishment_rules_view.xml',
65 'view/supplier_catalogue_view.xml',
66+ 'view/msf_import_export_view.xml',
67 'wizard/wizard_import_po_line_view.xml',
68 'wizard/wizard_import_fo_line.xml',
69 'wizard/wizard_import_tender_line.xml',
70
71=== modified file 'bin/addons/msf_doc_import/doc_import_report.xml'
72--- bin/addons/msf_doc_import/doc_import_report.xml 2016-07-27 08:54:22 +0000
73+++ bin/addons/msf_doc_import/doc_import_report.xml 2017-09-12 08:08:04 +0000
74@@ -45,5 +45,16 @@
75 auto="False"
76 string="Import Generic template" />
77
78+ <report
79+ id="wizard_export_generic"
80+ model="msf.import.export"
81+ name="wizard.export.generic"
82+ file="msf_doc_import/report/export_generic.mako"
83+ report_type="webkit"
84+ header="False"
85+ menu="False"
86+ auto="False"
87+ string="Generic Export" />
88+
89 </data>
90 </openerp>
91
92=== added file 'bin/addons/msf_doc_import/msf_import_export.py'
93--- bin/addons/msf_doc_import/msf_import_export.py 1970-01-01 00:00:00 +0000
94+++ bin/addons/msf_doc_import/msf_import_export.py 2017-09-12 08:08:04 +0000
95@@ -0,0 +1,792 @@
96+# encoding: utf-8
97+##############################################################################
98+#
99+# OpenERP, Open Source Management Solution
100+# Copyright (C) 2017 MSF, TeMPO Consulting
101+#
102+# This program is free software: you can redistribute it and/or modify
103+# it under the terms of the GNU General Public License as published by
104+# the Free Software Foundation, either version 3 of the License, or
105+# (at your option) any later version.
106+#
107+# This program is distributed in the hope that it will be useful,
108+# but WITHOUT ANY WARRANTY; without even the implied warranty of
109+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110+# GNU General Public License for more details.
111+#
112+# You should have received a copy of the GNU General Public License
113+# along with this program. If not, see <http://www.gnu.org/licenses/>.
114+#
115+##############################################################################
116+
117+import base64
118+import time
119+import threading
120+import logging
121+
122+import pooler
123+import tools
124+
125+from osv import fields
126+from osv import osv
127+from tools.translate import _
128+
129+from tempfile import TemporaryFile
130+from lxml import etree
131+from lxml.etree import XMLSyntaxError
132+
133+from msf_doc_import.wizard.abstract_wizard_import import ImportHeader
134+from msf_doc_import.msf_import_export_conf import MODEL_DICT
135+from msf_doc_import.msf_import_export_conf import MODEL_DATA_DICT
136+
137+MIN_COLUMN_SIZE = 40
138+MAX_COLUMN_SIZE = 400
139+
140+class msf_import_export(osv.osv_memory):
141+ _name = 'msf.import.export'
142+ _description = 'MSF Import Export'
143+ _inherit = 'abstract.wizard.import'
144+
145+ def _get_model_list(self, cr, uid, context=None):
146+ """The list of available model depend on the menu entry selected
147+ """
148+ if context is None:
149+ context = {}
150+ domain_type = None
151+ if 'domain_type' in context:
152+ domain_type = context['domain_type']
153+ result_list = [(key, _(value['name'])) for key, value in MODEL_DICT.items() if value['domain_type'] == domain_type]
154+ return [('', '')] + sorted(result_list, key=lambda a: a[0])
155+
156+ _columns = {
157+ 'display_file_import': fields.boolean('File Import'),
158+ 'display_file_export': fields.boolean('File Export'),
159+ 'model_list_selection': fields.selection(selection=_get_model_list, string='Object to Import/Export', required=True),
160+ 'import_file': fields.binary('File to import .xml'),
161+ 'hide_download_3_entries': fields.boolean('Hide export 3 entries button'),
162+ 'hide_download_all_entries': fields.boolean('Hide export all entries button'),
163+ 'display_test_import_button': fields.boolean('Display test import button'),
164+ }
165+
166+ _default = {
167+ 'display_file_import': lambda *a: False,
168+ 'display_file_export': lambda *a: False,
169+ 'hide_download_3_entries': lambda *a: False,
170+ 'hide_download_all_entries': lambda *a: False,
171+ 'display_test_import_button': lambda *a: False,
172+ }
173+
174+ def get_filename(self, cr, uid, model, selection, template_only=False, context=None):
175+ """Generate a filename for the import/export
176+ """
177+ model_obj = self.pool.get(model)
178+ file_name = _(MODEL_DICT[selection]['name'])
179+ file_name = file_name.replace(' ', '_')
180+ if template_only:
181+ file_name = _('%s_Import_Template') % file_name
182+ else:
183+ file_name = _('%s_Export_%s') % (file_name, time.strftime('%Y%m%d'))
184+ return file_name
185+
186+ def generic_download(self, cr, uid, ids, template_only=False,
187+ nb_lines=None, context=None):
188+ """Mutualise the code of all download buttons in one place
189+ """
190+ if context is None:
191+ context = {}
192+ if isinstance(ids, (int, long)):
193+ ids = [ids]
194+
195+ wiz = self.browse(cr, uid, ids[0])
196+ selection = wiz.model_list_selection
197+ model = MODEL_DICT[selection]['model']
198+ if selection not in MODEL_DATA_DICT:
199+ raise osv.except_osv(_('Error'),
200+ _('Selection \'%s\' not found. '
201+ 'Please contact the support team.') % (selection))
202+
203+ if 'header_list' not in MODEL_DATA_DICT[selection]:
204+ raise osv.except_osv(_('Error'),
205+ _('The header_list for report \'%s\' is not'
206+ ' defined. Please contact the support team.') % (selection))
207+ fields = MODEL_DATA_DICT[selection]['header_list']
208+ domain = MODEL_DICT[selection].get('domain', [])
209+ context['translate_selection_field'] = True
210+ data = {
211+ 'model': model,
212+ 'fields': fields,
213+ 'nb_lines': nb_lines,
214+ 'template_only': template_only,
215+ 'domain': domain,
216+ 'target_filename': self.get_filename(cr, uid, model, selection, template_only),
217+ }
218+ return {
219+ 'type': 'ir.actions.report.xml',
220+ 'report_name': 'wizard.export.generic',
221+ 'datas': data,
222+ 'context': context,
223+ }
224+
225+ def download_all_entries_file(self, cr, uid, ids, context=None):
226+ """Download a template filled with all datas of the modele
227+ """
228+ return self.generic_download(cr, uid, ids, context=context)
229+
230+ def download_3_entries_file(self, cr, uid, ids, context=None):
231+ """Download a template filled with the first 3 lines of data
232+ """
233+ return self.generic_download(cr, uid, ids, nb_lines=3, context=context)
234+
235+ def download_template_file(self, cr, uid, ids, context=None):
236+ """Download the template file (without any data)
237+ """
238+ return self.generic_download(cr, uid, ids, template_only=True,
239+ context=context)
240+
241+ def get_excel_size_from_string(self, string):
242+ """Compute the string to get the size of it in a excel
243+ understandable value
244+ :param string: the str chain to get the excel size
245+ :return: A int instance
246+ """
247+ # this calculation is used to translate the
248+ # character len to an excel understandable len
249+
250+ max_digit_width = 7 # For Calabri 11 which is the font used in our reports
251+ conversion_factor = 3/4. # to convert from pixel to points
252+ padding = 15
253+
254+ # this formule partially come from readings here:
255+ # http://stackoverflow.com/questions/4577546/calculating-height-width-and-ysplit-xsplit-for-open-xml-spreadsheets?answertab=votes#tab-top
256+ size = round(max_digit_width*len(string)*conversion_factor+padding)
257+
258+ # set a max and min len for the columns to avoid ridiculus column size
259+ size = min(size, MAX_COLUMN_SIZE)
260+ size = max(size, MIN_COLUMN_SIZE)
261+ return size
262+
263+ def get_child_field(self, cr, uid, field, model, fields_get_dict,
264+ context=None):
265+ if context is None:
266+ context = {}
267+ if '.' in field:
268+ model_obj = self.pool.get(model)
269+ if model not in fields_get_dict:
270+ fields_get_res = model_obj.fields_get(cr, uid, context=context)
271+ fields_get_dict[model] = fields_get_res
272+ else:
273+ fields_get_res = fields_get_dict[model]
274+
275+
276+ child_field = field.split('.')[0]
277+ rest = '.'.join(field.split('.')[1:])
278+
279+ if child_field not in fields_get_res:
280+ raise osv.except_osv(_('Error'),
281+ _('field \'%s\' not found for model \'%s\'. Please contact the support team.')
282+ % (child_field, model))
283+
284+ #if child and child !='id' and fields_get_res[child_field].get('relation'):
285+ child_model = fields_get_res[child_field]['relation']
286+ if child_model not in fields_get_dict:
287+ model_obj = self.pool.get(child_model)
288+ fields_get_res = model_obj.fields_get(cr, uid, context=context)
289+ fields_get_dict[child_model] = fields_get_res
290+ return self.get_child_field(cr, uid, rest, child_model, fields_get_dict,
291+ context=context)
292+ else:
293+ return field, model
294+
295+ def _get_headers(self, cr, uid, model, selection=None, field_list=None, rows=None, context=None):
296+ """Generate a list of ImportHeader objects using the data that retived
297+ from the field name.
298+ :param model: Model of the object imported/exported
299+ :param selection: requried to get the list of fields to compose the header
300+ :param field_list: if known, the list of the fields to display in the
301+ header can be passed
302+ :param rows: Data rows to export. In case of export, the size of the
303+ columns matter and can be determinied according to the data string length
304+ :param context: Context of the call, this is particularly important to
305+ get the language for tranlsating the fields.
306+ :return: A list of ImportHeader
307+ """
308+ if context is None:
309+ context = {}
310+ headers = []
311+ if not field_list:
312+ field_list = MODEL_DATA_DICT[selection]['header_list']
313+ model_obj = self.pool.get(model)
314+
315+ fields_get_dict = {} # keep fields_get result in cache
316+ fields_get_dict[model] = model_obj.fields_get(cr, uid, context=context)
317+
318+ for field_index, field in enumerate(field_list):
319+ res = {'tech_name': field}
320+ if selection and field in MODEL_DATA_DICT[selection]['required_field_list']:
321+ res['required'] = True
322+ child_field, child_model = self.get_child_field(cr, uid, field, model,
323+ fields_get_dict, context=context)
324+ first_part = field.split('.')[0]
325+ if first_part not in fields_get_dict[model]:
326+ raise osv.except_osv(_('Error'),
327+ _('field \'%s\' not found for model \'%s\'. Please contact the support team.')
328+ % (first_part, model))
329+ if first_part != child_field:
330+ if child_field not in fields_get_dict[child_model]:
331+ raise osv.except_osv(_('Error'),
332+ _('field \'%s\' not found for model \'%s\'. Please contact the support team.')
333+ % (child_field, child_model))
334+ res['name'] = '%s / %s' % (fields_get_dict[model][first_part]['string'],
335+ fields_get_dict[child_model][child_field]['string'])
336+ else:
337+ res['name'] = fields_get_dict[model][first_part]['string']
338+
339+
340+ field_type = fields_get_dict[child_model][child_field]['type']
341+ if field_type == 'boolean':
342+ res['ftype'] = 'Boolean'
343+ elif field_type == 'float':
344+ res['ftype'] = 'Float'
345+ elif field_type == 'integer':
346+ res['ftype'] = 'Number'
347+ else:
348+ res['ftype'] = 'String'
349+
350+ if not rows:
351+ # if no data passed, set the column size with the size of the header name
352+ res['size'] = self.get_excel_size_from_string(res['name'])
353+ else:
354+ # automatically set the width of the column by searching for the
355+ # biggest string in this column
356+ all_cells_chain = [tools.ustr(x[field_index]) for x in rows]
357+ res['size'] = MIN_COLUMN_SIZE
358+ if all_cells_chain:
359+ longest_chain = max(all_cells_chain, key=len)
360+ if longest_chain:
361+ res['size'] = self.get_excel_size_from_string(longest_chain)
362+ headers.append(ImportHeader(**res))
363+ return headers
364+
365+ def domain_type_change(self, cr, uid, ids, model_list_selection, context=None):
366+ """When the type of object to import/export change, change the buttons
367+ to display or not according to the new object model
368+ """
369+ if context is None:
370+ context = {}
371+ result = {'value': {}}
372+ result['value']['display_file_import'] = True
373+ result['value']['display_file_export'] = True
374+ if model_list_selection:
375+ if model_list_selection and model_list_selection in MODEL_DATA_DICT:
376+ hide_export = MODEL_DATA_DICT[model_list_selection].get('hide_export', False)
377+ result['value']['display_file_export'] = not hide_export
378+ hide_3 = MODEL_DATA_DICT[model_list_selection].get('hide_download_3_entries', False)
379+ result['value']['hide_download_3_entries'] = hide_3
380+ hide_all = MODEL_DATA_DICT[model_list_selection].get('hide_download_all_entries', False)
381+ result['value']['hide_download_all_entries'] = hide_all
382+ else:
383+ result['value']['hide_download_3_entries'] = False
384+ result['value']['hide_download_all_entries'] = False
385+ return result
386+
387+ def file_change(self, cr, uid, obj_id, import_file, context=None):
388+ """Display the import button only if a file as been selected
389+ """
390+ if context is None:
391+ context = {}
392+ result = {'value': {'display_test_import_button': False}}
393+ if import_file:
394+ result['value']['display_test_import_button'] = True
395+ return result
396+
397+ def check_xml_syntax(self, cr, uid, xml_string, context=None):
398+ """Try to parse the xml file and raise if there is an error
399+ """
400+ try:
401+ file_dom = etree.fromstring(xml_string)
402+ except XMLSyntaxError as e:
403+ raise osv.except_osv(_('Error'), _('File structure is incorrect, '
404+ 'please correct. You may generate a template with the File '
405+ 'export functionality.'))
406+
407+ def test_import(self, cr, uid, ids, context=None):
408+ """Warn if file structure is correct
409+ """
410+ if self.check_import(cr, uid, ids, context=context):
411+ raise osv.except_osv(_('Info'), _('File structure is correct.'))
412+
413+ def check_import(self, cr, uid, ids, context=None):
414+ """Verify that a file has been selected and all columns expected are
415+ present
416+ """
417+ obj = self.read(cr, uid, ids[0])
418+ if not obj['import_file']:
419+ raise osv.except_osv(_('Error'), _('Nothing to import.'))
420+ fileobj = TemporaryFile('w+')
421+ try:
422+ xml_string = base64.decodestring(obj['import_file'])
423+ self.check_xml_syntax(cr, uid, xml_string, context=context)
424+ for wiz in self.browse(cr, uid, ids, context=context):
425+ selection = wiz.model_list_selection
426+ model = MODEL_DICT[selection]['model']
427+ if model == 'user.access.configurator':
428+ continue
429+ rows, nb_rows = self.read_file(wiz, context=context)
430+ head = rows.next()
431+ self.check_missing_columns(cr, uid, wiz, head, context=context)
432+ finally:
433+ fileobj.close()
434+ return True
435+
436+ def excel_col(self, col):
437+ """Covert column number (1,2,...26,27,28...) to excel-style column label
438+ letters (A,B,..Z,AA,AB,...)."""
439+ quot, rem = divmod(col-1,26)
440+ return self.excel_col(quot) + chr(rem+ord('A')) if col!=0 else ''
441+
442+ def check_missing_columns(self, cr, uid, wizard_brw, head, context=None):
443+ """Check that the column names in the file match the expected property
444+ names, raise if any column is missing.
445+ """
446+ selection = wizard_brw.model_list_selection
447+ model = MODEL_DICT[selection]['model']
448+ model_obj = self.pool.get(model)
449+ header_columns = [head[i].data for i in range(0, len(head))]
450+ missing_columns = []
451+ field_list = MODEL_DATA_DICT[selection]['header_list']
452+
453+ fields_get_dict = {} # keep fields_get result in cache
454+ fields_get_dict[model] = model_obj.fields_get(cr, uid, context=context)
455+ fields_get_res = model_obj.fields_get(cr, uid,
456+ [x.split('.')[0] for x in field_list], context=context)
457+ if len(field_list) != len(header_columns):
458+ raise osv.except_osv(_('Info'), _('The number of column is not same ' \
459+ 'than expected (get %s, expected %s). Check your import file and ' \
460+ 'the Object to import/export.') % (len(header_columns), len(field_list)))
461+
462+ for field_index, field in enumerate(field_list):
463+ child_field, child_model = self.get_child_field(cr, uid, field, model,
464+ fields_get_dict, context=context)
465+ first_part = field.split('.')[0]
466+ if first_part not in fields_get_dict[model]:
467+ raise osv.except_osv(_('Error'),
468+ _('field \'%s\' not found for model \'%s\'. Please contact the support team.')
469+ % (first_part, model))
470+ if first_part != child_field:
471+ if child_field not in fields_get_dict[child_model]:
472+ raise osv.except_osv(_('Error'),
473+ _('field \'%s\' not found for model \'%s\'. Please contact the support team.')
474+ % (child_field, child_model))
475+ column_name = '%s / %s' % (fields_get_dict[model][first_part]['string'],
476+ fields_get_dict[child_model][child_field]['string'])
477+ else:
478+ column_name = fields_get_dict[model][first_part]['string']
479+
480+ if column_name.upper() != header_columns[field_index].upper():
481+ missing_columns.append(_('Column %s: get \'%s\' expected \'%s\'.')
482+ % (self.excel_col(field_index+1), header_columns[field_index], column_name))
483+ if missing_columns:
484+ raise osv.except_osv(_('Info'), _('The following columns '
485+ 'are missing in the imported file:\n%s') % ',\n'.join(missing_columns))
486+
487+ def import_xml(self, cr, uid, ids, context=None):
488+ """Create a thread to import the data after import checking
489+ """
490+ if context is None:
491+ context = {}
492+ if isinstance(ids, (int, long)):
493+ ids = [ids]
494+
495+ self.check_import(cr, uid, ids, context=context)
496+
497+ for wiz in self.browse(cr, uid, ids, context=context):
498+ rows, nb_rows = self.read_file(wiz, context=context)
499+ head = rows.next()
500+ selection = wiz.model_list_selection
501+ model = MODEL_DICT[selection]['model']
502+
503+ if model == 'user.access.configurator':
504+ # special case handling for this one
505+ model_obj = self.pool.get(model)
506+ wizard_id = model_obj.create(cr, uid, {}, context)
507+ model_obj.write(cr, uid, [wizard_id], {'file_to_import_uac':
508+ wiz.import_file}, context=context)
509+ return model_obj.do_process_uac(cr, uid, [wizard_id], context=context)
510+
511+ expected_headers = self._get_headers(cr, uid, model, selection=selection, context=context)
512+ if model != 'user.access.configurator':
513+ self.check_headers(head, expected_headers, context=context)
514+
515+ self.write(cr, uid, [wiz.id], {
516+ 'total_lines_to_import': nb_rows,
517+ 'state': 'progress',
518+ 'start_date': time.strftime('%Y-%m-%d %H:%M:%S'),
519+ 'info_message': _('Import in progress, please leave this window open and press the button \'Update\' '
520+ 'to show the progression of the import. Otherwise, you can continue to use Unifield'),
521+ }, context=context)
522+ wiz.total_lines_to_import = nb_rows
523+
524+ thread = threading.Thread(
525+ target=self.bg_import,
526+ args=(cr.dbname, uid, wiz, expected_headers, rows, context),
527+ )
528+ thread.start()
529+ # for now we don't want background but foreground
530+ # in case background is needed, just set a value to wait time
531+ wait_time = None
532+ thread.join(wait_time)
533+ return True
534+
535+ def bg_import(self, dbname, uid, import_brw, headers, rows, context=None):
536+ """
537+ Run the import of lines in background
538+ :param dbname: Name of the database
539+ :param uid: ID of the res.users that calls this method
540+ :param import_brw: browse_record of a wizard.import.batch
541+ :param headers: List of expected headers
542+ :param rows: Iterator on file rows
543+ :param context: Context of the call
544+ :return: True
545+ """
546+ if context is None:
547+ context = {}
548+ cr = pooler.get_db(dbname).cursor()
549+ model = MODEL_DICT[import_brw.model_list_selection]['model']
550+ impobj = self.pool.get(model)
551+
552+ import_data_obj = self.pool.get('import_data')
553+ prod_nomenclature_obj = self.pool.get('product.nomenclature')
554+
555+ # Manage errors
556+ import_errors = {}
557+
558+ def save_error(errors, row_index):
559+ if not isinstance(errors, list):
560+ errors = [errors]
561+ import_errors.setdefault(row_index+2, [])
562+ import_errors[row_index+2].extend(errors)
563+
564+ # Manage warnings
565+ import_warnings = {}
566+
567+ def save_warnings(warnings):
568+ if not isinstance(warnings, list):
569+ warnings = [warnings]
570+ import_warnings.setdefault(row_index+2, [])
571+ import_warnings[row_index+2].extend(warnings)
572+
573+ start_time = time.time()
574+
575+ if model == 'product.product':
576+ # Create the cache
577+ if not hasattr(self, '_cache'):
578+ self._cache = {}
579+ self._cache.setdefault(dbname, {})
580+
581+ if not hasattr(prod_nomenclature_obj, '_cache'):
582+ prod_nomenclature_obj._cache = {}
583+ prod_nomenclature_obj._cache.setdefault(dbname, {})
584+
585+ # Clear the cache
586+ self._cache[dbname] = {'product.nomenclature': {'name': {}, 'complete_name': {}},
587+ 'product.uom': {'name': {}},
588+ 'product.asset.type': {'name': {}},
589+ 'product.international.status': {'name': {}},
590+ }
591+ # Product nomenclature
592+ cr.execute('SELECT name, id FROM product_nomenclature;')
593+ for nv in cr.dictfetchall():
594+ self._cache[dbname]['product.nomenclature']['name'].update({nv['name']: nv['id']})
595+ # Product category
596+ cr.execute('SELECT id, family_id FROM product_category;')
597+ for pc in cr.dictfetchall():
598+ prod_nomenclature_obj._cache[dbname].update({pc['family_id']: pc['id']})
599+ # Product nomenclature complete name
600+ cr.execute('''SELECT id, name FROM
601+(
602+(SELECT
603+ n0.id, n0.name AS name
604+FROM product_nomenclature n0
605+WHERE n0.level = 0)
606+UNION
607+(SELECT n1.id, n0.name ||' | '|| n1.name AS name
608+FROM product_nomenclature n1
609+ LEFT JOIN product_nomenclature n0 ON n1.parent_id = n0.id
610+WHERE n1.level = 1)
611+UNION
612+(SELECT n2.id, n0.name ||' | '|| n1.name ||' | '|| n2.name AS name
613+FROM product_nomenclature n1
614+ LEFT JOIN product_nomenclature n0 ON n1.parent_id = n0.id
615+ LEFT JOIN product_nomenclature n2 ON n2.parent_id = n1.id
616+WHERE n2.level = 2)
617+UNION
618+(SELECT n3.id, n0.name ||' | '|| n1.name ||' | '|| n2.name ||' | '|| n3.name AS name
619+FROM product_nomenclature n1
620+ LEFT JOIN product_nomenclature n0 ON n1.parent_id = n0.id
621+ LEFT JOIN product_nomenclature n2 ON n2.parent_id = n1.id
622+ LEFT JOIN product_nomenclature n3 ON n3.parent_id = n2.id
623+WHERE n3.level = 3)
624+) AS cn''')
625+ for cnv in cr.dictfetchall():
626+ self._cache[dbname]['product.nomenclature']['complete_name'].update({cnv['name']: cnv['id']})
627+ # Product UoM
628+ cr.execute('SELECT name, id FROM product_uom;')
629+ for uv in cr.dictfetchall():
630+ self._cache[dbname]['product.uom']['name'].update({uv['name']: uv['id']})
631+ # Asset type
632+ cr.execute('SELECT name, id FROM product_asset_type;')
633+ for av in cr.dictfetchall():
634+ self._cache[dbname]['product.asset.type']['name'].update({av['name']: av['id']})
635+ # International status
636+ cr.execute('SELECT name, id FROM product_international_status;')
637+ for iv in cr.dictfetchall():
638+ self._cache[dbname]['product.international.status']['name'].update({iv['name']: iv['id']})
639+
640+ fields_def = impobj.fields_get(cr, uid, context=context)
641+ i = 0
642+
643+ def _get_obj(header, value, fields_def):
644+ list_obj = header.split('.')
645+ relation = fields_def[list_obj[0]]['relation']
646+ if impobj._name == 'product.product' and value in self._cache.get(dbname, {}).get(relation, {}).get(list_obj[1], {}):
647+ return self._cache[dbname][relation][list_obj[1]][value]
648+ new_obj = self.pool.get(relation)
649+ newids = new_obj.search(cr, uid, [(list_obj[1], '=', value)], limit=1)
650+ if not newids:
651+ # no obj
652+ raise osv.except_osv(_('Warning !'), _('%s \'%s\' does not exist') % (new_obj._description, value,))
653+
654+ if impobj._name == 'product.product':
655+ self._cache[dbname].setdefault(relation, {})
656+ self._cache[dbname][relation].setdefault(list_obj[1], {})
657+ self._cache[dbname][relation][list_obj[1]][value] = newids[0]
658+ return newids[0]
659+
660+ def process_data(field, value, fields_def):
661+ if value is None or field not in fields_def:
662+ return
663+ if '.' not in field:
664+ if fields_def[field]['type'] == 'selection':
665+ if impobj == 'product.product' and self._cache[dbname].get('product.product.%s.%s' % (field, value), False):
666+ value = self._cache[dbname]['product.product.%s.%s' % (field, value)]
667+ else:
668+ for key, val in fields_def[field]['selection']:
669+ if value.lower() in [tools.ustr(key).lower(), tools.ustr(val).lower()]:
670+ value = key
671+ if impobj == 'product.product':
672+ self._cache[dbname].setdefault('product.product.%s' % field, {})
673+ self._cache[dbname]['product.product.%s.%s' % (field, value)] = key
674+ break
675+ return value
676+
677+ else:
678+ if fields_def[field.split('.')[0]]['type'] in 'many2one':
679+ return _get_obj(field, value, fields_def)
680+
681+ raise osv.except_osv(_('Warning !'), _('%s does not exist')%(value,))
682+
683+ i = 1
684+ nb_error = 0
685+ nb_succes = 0
686+ nb_update_success = 0
687+ col_datas = {}
688+ nb_imported_lines = 0
689+ header_codes = [x[3] for x in headers]
690+ if import_data_obj.pre_hook.get(impobj._name):
691+ # for headers mod.
692+ col_datas = import_data_obj.pre_hook[impobj._name](impobj, cr, uid, header_codes, {}, col_datas)
693+
694+ for row_index, row in enumerate(rows):
695+ res, errors, line_data = self.check_error_and_format_row(import_brw.id, row, headers, context=context)
696+ if res < 0:
697+ save_error(errors, row_index)
698+ continue
699+
700+ if all(not x for x in line_data):
701+ save_warnings(
702+ _('Line seemed empty, so this line was ignored')
703+ )
704+ continue
705+
706+ newo2m = False
707+ delimiter = False
708+ o2mdatas = {}
709+ i += 1
710+ data = {}
711+ try:
712+ if model == 'hq.entries':
713+ hq_entries_obj = self.pool.get('hq.entries.import')
714+ hq_entries_obj.update_hq_entries(cr, uid, line_data, context=context)
715+ continue
716+
717+ n = 0
718+ line_ok = True
719+ if import_data_obj.pre_hook.get(impobj._name):
720+ import_data_obj.pre_hook[impobj._name](impobj, cr, uid, header_codes, line_data, col_datas)
721+
722+ for n, h in enumerate(header_codes):
723+ if isinstance(line_data[n], basestring):
724+ line_data[n] = line_data[n].rstrip()
725+ if len(line_data[n].splitlines()) > 1:
726+ # US-2661 do not allowed newline character in char fields
727+ save_error(_("New line characters in the field '%s' not allowed. Please fix entry :\n'%s'") % (h, line_data[n]), row_index)
728+ nb_error += 1
729+ line_ok = False
730+ break
731+
732+ # UFTP-327
733+ # if required reject cells with exceeded field length
734+ if 'import_data_field_max_size' in context:
735+ if h in context['import_data_field_max_size']:
736+ max_size = context['import_data_field_max_size'][h]
737+ if len(line_data[n]) > max_size:
738+ msg_tpl = "field '%s' value exceed field length of %d"
739+ msg = msg_tpl % (h , max_size, )
740+ logging.getLogger('import data').info(
741+ 'Error %s'% (msg, ))
742+ cr.rollback()
743+ error = "Line %s, row: %s, %s" % (i, n, msg, )
744+ save_error(error, row_index)
745+ nb_error += 1
746+ line_ok = False
747+ break
748+
749+ if newo2m and ('.' not in h or h.split('.')[0] != newo2m or h.split('.')[1] == delimiter):
750+ data.setdefault(newo2m, []).append((0, 0, o2mdatas.copy()))
751+ o2mdatas = {}
752+ delimiter = False
753+ newo2m = False
754+ if '.' not in h:
755+ # type datetime, date, bool, int, float
756+ value = process_data(h, line_data[n], fields_def)
757+ if value is not None:
758+ data[h] = value
759+ else:
760+ points = h.split('.')
761+ if row[n] and fields_def[points[0]]['type'] == 'one2many':
762+ newo2m = points[0]
763+ delimiter = points[1]
764+ new_fields_def = self.pool.get(fields_def[newo2m]['relation']).fields_get(cr, uid, context=context)
765+ o2mdatas[points[1]] = process_data('.'.join(points[1:]), line_data[n], new_fields_def)
766+ elif fields_def[points[0]]['type'] in 'many2one':
767+ if not line_data[n]:
768+ data[points[0]] = False
769+ elif line_data[n]:
770+ data[points[0]] = _get_obj(h, line_data[n], fields_def) or False
771+ elif fields_def[points[0]]['type'] in 'many2many' and line_data[n]:
772+ data.setdefault(points[0], []).append((4, _get_obj(h, line_data[n], fields_def)))
773+ if not line_ok:
774+ continue
775+ if newo2m and o2mdatas:
776+ data.setdefault(newo2m, []).append((0, 0, o2mdatas.copy()))
777+
778+ if import_data_obj.post_hook.get(impobj._name):
779+ import_data_obj.post_hook[impobj._name](impobj, cr, uid, data, line_data, header_codes)
780+
781+ # Search if an object already exist. If not, create it.
782+ ids_to_update = []
783+
784+ if impobj._name == 'product.product':
785+ # Allow to update the product, use xmlid_code or default_code
786+ if 'xmlid_code' in data:
787+ ids_to_update = impobj.search(cr, uid, [('xmlid_code',
788+ '=', data['xmlid_code'])], order='NO_ORDER')
789+ if 'default_code' in data:
790+ ids_to_update = impobj.search(cr, uid, [('default_code',
791+ '=', data['default_code'])], order='NO_ORDER')
792+ elif impobj._name == 'product.nomenclature':
793+ ids_to_update = impobj.search(cr, uid, [('msfid', '=',
794+ data['msfid'])], order='NO_ORDER')
795+ elif impobj._name == 'product.category':
796+ ids_to_update = impobj.search(cr, uid, [('msfid', '=',
797+ data['msfid'])], order='NO_ORDER')
798+
799+ if ids_to_update:
800+ #UF-2170: remove the standard price value from the list for update product case
801+ if 'standard_price' in data:
802+ del data['standard_price']
803+ impobj.write(cr, uid, ids_to_update, data)
804+ nb_update_success += 1
805+
806+ else:
807+ impobj.create(cr, uid, data, context={'from_import_menu': True})
808+ nb_succes += 1
809+ except osv.except_osv, e:
810+ logging.getLogger('import data').info('Error %s' % e.value)
811+ cr.rollback()
812+ save_error(e.value, row_index)
813+ nb_error += 1
814+ except Exception, e:
815+ cr.rollback()
816+ logging.getLogger('import data').info('Error %s' % e)
817+ save_error(e, row_index)
818+ nb_error += 1
819+ else:
820+ nb_imported_lines += 1
821+
822+ self.write(cr, uid, [import_brw.id], {'total_lines_imported': nb_imported_lines}, context=context)
823+
824+ warn_msg = ''
825+ for line_number in sorted(import_warnings.keys()):
826+ warnings = import_warnings[line_number]
827+ for warn in warnings:
828+ warn_msg += _('Line %s: %s') % (line, warn)
829+ if not warn_msg.endswith('\n'):
830+ warn_msg += '\n'
831+
832+ err_msg = ''
833+ for line_number in sorted(import_errors.keys()):
834+ errors = import_errors[line_number]
835+ for err in errors:
836+ err_msg += _('Line %s: %s') % (line_number, err)
837+ if not err_msg.endswith('\n'):
838+ err_msg += '\n'
839+
840+ if err_msg:
841+ cr.rollback()
842+
843+ info_msg = _('''Processing of file completed in %s second(s)!
844+- Total lines to import: %s
845+- Total lines %s: %s %s
846+- Total lines with errors: %s %s
847+%s
848+ ''') % (
849+ str(round(time.time() - start_time, 1)),
850+ import_brw.total_lines_to_import-1,
851+ err_msg and _('without errors') or _('imported'),
852+ nb_imported_lines,
853+ warn_msg and _('(%s line(s) with warning - see warning messages below)') % (
854+ len(import_warnings.keys()) or '',
855+ ),
856+ err_msg and len(import_errors.keys()) or 0,
857+ err_msg and _('(see error messages below)'),
858+ err_msg and _("no data will be imported until all the error messages are corrected") or '',
859+ )
860+
861+ self.write(cr, uid, [import_brw.id], {
862+ 'error_message': err_msg,
863+ 'show_error': err_msg and True or False,
864+ 'warning_message': warn_msg,
865+ 'show_warning': warn_msg and True or False,
866+ 'info_message': info_msg,
867+ 'state': 'done',
868+ 'end_date': time.strftime('%Y-%m-%d %H:%M:%S'),
869+ }, context=context)
870+
871+ if import_data_obj.post_load_hook.get(impobj._name):
872+ import_data_obj.post_load_hook[impobj._name](impobj, cr, uid)
873+
874+ if impobj == 'product.product':
875+ # Clear the cache
876+ self._cache[dbname] = {}
877+ prod_nomenclature_obj._cache[dbname] = {}
878+
879+
880+ cr.commit()
881+ cr.close()
882+
883+ return True
884+
885+msf_import_export()
886+
887+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
888
889=== added file 'bin/addons/msf_doc_import/msf_import_export_conf.py'
890--- bin/addons/msf_doc_import/msf_import_export_conf.py 1970-01-01 00:00:00 +0000
891+++ bin/addons/msf_doc_import/msf_import_export_conf.py 2017-09-12 08:08:04 +0000
892@@ -0,0 +1,530 @@
893+# encoding: utf-8
894+##############################################################################
895+#
896+# OpenERP, Open Source Management Solution
897+# Copyright (C) 2017 MSF, TeMPO Consulting
898+#
899+# This program is free software: you can redistribute it and/or modify
900+# it under the terms of the GNU General Public License as published by
901+# the Free Software Foundation, either version 3 of the License, or
902+# (at your option) any later version.
903+#
904+# This program is distributed in the hope that it will be useful,
905+# but WITHOUT ANY WARRANTY; without even the implied warranty of
906+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
907+# GNU General Public License for more details.
908+#
909+# You should have received a copy of the GNU General Public License
910+# along with this program. If not, see <http://www.gnu.org/licenses/>.
911+#
912+##############################################################################
913+
914+from tools.translate import _
915+
916+MODEL_DICT = {
917+ # SUPPLY
918+ 'products': {
919+ 'name': 'Products',
920+ 'domain_type': 'supply',
921+ 'model': 'product.product',
922+ },
923+ 'product_nomenclature': {
924+ 'name': 'Product Nomenclature',
925+ 'domain_type': 'supply',
926+ 'model': 'product.nomenclature',
927+ },
928+ 'product_category': {
929+ 'name': 'Product Categories',
930+ 'domain_type': 'supply',
931+ 'model': 'product.category',
932+ },
933+ 'suppliers': {
934+ 'name': 'Suppliers',
935+ 'domain_type': 'supply',
936+ 'model': 'res.partner',
937+ 'domain': [('supplier', '=', True)],
938+ },
939+ 'supplier_catalogues': {
940+ 'name': 'Supplier Catalogues',
941+ 'domain_type': 'supply',
942+ 'model': 'supplier.catalogue',
943+ },
944+ 'supplier_catalogues_lines': {
945+ 'name': 'Supplier catalogue lines',
946+ 'domain_type': 'supply',
947+ 'model': 'supplier.catalogue.line',
948+ },
949+
950+
951+ # FINANCE
952+ 'gl_accounts': {
953+ 'name': 'GL Accounts',
954+ 'domain_type': 'finance',
955+ 'model': 'account.account'
956+ },
957+ 'gl_journals': {
958+ 'name': 'GL Journals',
959+ 'domain_type': 'finance',
960+ 'model': 'account.journal'
961+ },
962+ 'analytic_accounts': {
963+ 'name': 'Analytic Accounts',
964+ 'domain_type': 'finance',
965+ 'model': 'account.analytic.account'
966+ },
967+ 'analytic_journals': {
968+ 'name': 'Analytic Journals',
969+ 'domain_type': 'finance',
970+ 'model': 'account.analytic.journal'
971+ },
972+ 'employees': {
973+ 'name': 'Employees',
974+ 'domain_type': 'finance',
975+ 'model': 'hr.employee'
976+ },
977+ 'hq_entries': {
978+ 'name': 'HQ Entries',
979+ 'domain_type': 'finance',
980+ 'model': 'hq.entries'
981+ },
982+ 'currency_rate': {
983+ 'name': 'Currencies Rates',
984+ 'domain_type': 'finance',
985+ 'model': 'res.currency.rate'
986+ },
987+
988+
989+ # NON FUNCTIONNAL
990+ 'user_groups': {
991+ 'name': 'User Groups',
992+ 'domain_type': 'non_functionnal',
993+ 'model': 'res.groups'
994+ },
995+ 'user_access': {
996+ 'name': 'User Access',
997+ 'domain_type': 'non_functionnal',
998+ 'model': 'user.access.configurator'
999+ },
1000+ 'record_rules': {
1001+ 'name': 'Record Rules',
1002+ 'domain_type': 'non_functionnal',
1003+ 'model': 'ir.rule'
1004+ },
1005+ 'access_control_list': {
1006+ 'name': 'Access Controls List',
1007+ 'domain_type': 'non_functionnal',
1008+ 'model': 'ir.model.access'
1009+ },
1010+ 'field_access_rules': {
1011+ 'name': 'Field Access Rules',
1012+ 'domain_type': 'non_functionnal',
1013+ 'model': 'msf_field_access_rights.field_access_rule'
1014+ },
1015+ 'field_access_rule_lines': {
1016+ 'name': 'Field Access Rule Lines',
1017+ 'domain_type': 'non_functionnal',
1018+ 'model': 'msf_field_access_rights.field_access_rule_line'
1019+ },
1020+ 'button_access_rules': {
1021+ 'name': 'Button Access Rules',
1022+ 'domain_type': 'non_functionnal',
1023+ 'model': 'msf_button_access_rights.button_access_rule'
1024+ },
1025+ 'window_actions': {
1026+ 'name': 'Window Actions',
1027+ 'domain_type': 'non_functionnal',
1028+ 'model': 'ir.actions.act_window'
1029+ },
1030+}
1031+
1032+MODEL_DATA_DICT = {
1033+ # SUPPLY
1034+ 'products': {
1035+ 'header_list': [
1036+ 'default_code',
1037+ 'name',
1038+ 'xmlid_code',
1039+ 'old_code',
1040+ 'type',
1041+ 'transport_ok',
1042+ 'subtype',
1043+ 'asset_type_id.name',
1044+ 'procure_method',
1045+ 'supply_method',
1046+ 'standard_price',
1047+ 'volume',
1048+ 'weight',
1049+ 'international_status.name',
1050+ 'state.name',
1051+ 'active',
1052+ 'perishable',
1053+ 'batch_management',
1054+ 'uom_id.name',
1055+ 'uom_po_id.name',
1056+ 'nomen_manda_0.name',
1057+ 'nomen_manda_1.name',
1058+ 'nomen_manda_2.name',
1059+ 'nomen_manda_3.name',
1060+ 'life_time',
1061+ 'use_time',
1062+ 'short_shelf_life',
1063+ 'alert_time',
1064+ 'heat_sensitive_item.code',
1065+ 'cold_chain',
1066+ 'sterilized',
1067+ 'single_use',
1068+ 'narcotic',
1069+ 'justification_code_id.code',
1070+ 'controlled_substance',
1071+ 'closed_article',
1072+ 'restricted_country',
1073+ 'country_restriction',
1074+ 'dangerous_goods',
1075+ 'un_code',
1076+ 'criticism',
1077+ 'abc_class',
1078+ 'product_catalog_path',
1079+ 'description',
1080+ 'description2',
1081+ 'description_sale',
1082+ 'description_purchase',
1083+ 'procure_delay',
1084+ 'property_account_income.code',
1085+ 'property_account_expense.code',
1086+ ],
1087+ 'required_field_list': [
1088+ 'name',
1089+ 'international_status.name',
1090+ 'nomen_manda_0.name',
1091+ 'nomen_manda_1.name',
1092+ 'nomen_manda_2.name',
1093+ 'nomen_manda_3.name',
1094+ ],
1095+ 'hide_download_all_entries': True,
1096+ },
1097+ 'product_nomenclature': {
1098+ 'header_list': [
1099+ 'level',
1100+ 'name',
1101+ 'type',
1102+ 'parent_id.msfid',
1103+ 'msfid',
1104+ ],
1105+ 'required_field_list': [
1106+ 'level',
1107+ 'name',
1108+ ],
1109+ 'hide_download_3_entries': True,
1110+ 'hide_download_all_entries': True,
1111+ },
1112+ 'product_category': {
1113+ 'header_list': [
1114+ 'type',
1115+ 'property_account_expense_categ',
1116+ 'property_account_income_categ',
1117+ 'name',
1118+ 'property_stock_journal',
1119+ 'donation_expense_account',
1120+ 'family_id',
1121+ 'msfid',
1122+ ],
1123+ 'required_field_list': [
1124+ 'name',
1125+ 'family_id',
1126+ 'msfid',
1127+ ],
1128+ },
1129+ 'suppliers': {
1130+ 'header_list': [
1131+ 'address.type',
1132+ 'address.city',
1133+ 'address.name',
1134+ 'address.street',
1135+ 'address.zip',
1136+ 'address.country_id.name',
1137+ 'address.email',
1138+ 'property_account_payable.code',
1139+ 'property_account_receivable.code',
1140+ 'name',
1141+ 'lang',
1142+ 'partner_type',
1143+ 'customer',
1144+ 'supplier',
1145+ 'property_product_pricelist_purchase.currency_id',
1146+ 'property_product_pricelist.currency_id',
1147+ ],
1148+ 'required_field_list': [
1149+ 'property_account_payable.code',
1150+ 'property_account_receivable.code',
1151+ 'name',
1152+ ],
1153+ },
1154+ 'supplier_catalogues': {
1155+ 'header_list': [
1156+ 'name',
1157+ 'period_from',
1158+ 'period_to',
1159+ 'currency_id.name',
1160+ 'partner_id.name',
1161+ ],
1162+ 'required_field_list': [
1163+ 'name',
1164+ 'currency_id.name',
1165+ 'partner_id.name',
1166+ ],
1167+ },
1168+ 'supplier_catalogues_lines': {
1169+ 'header_list': [
1170+ 'catalogue_id.name',
1171+ 'product_id.code',
1172+ 'product_id.name',
1173+ 'line_uom_id.name',
1174+ 'min_qty',
1175+ 'unit_price',
1176+ 'rounding',
1177+ 'min_order_qty',
1178+ 'comment',
1179+ ],
1180+ 'required_field_list': [
1181+ 'catalogue_id.name',
1182+ 'product_id.code',
1183+ 'line_uom_id.name',
1184+ 'min_qty',
1185+ 'unit_price',
1186+ ],
1187+ },
1188+
1189+
1190+ # FINANCE
1191+ 'gl_accounts': {
1192+ 'header_list': [
1193+ 'user_type.code',
1194+ 'accrual_account',
1195+ 'activation_date',
1196+ 'code',
1197+ 'default_destination_id.code',
1198+ 'inactivation_date',
1199+ 'type',
1200+ 'name',
1201+ 'note',
1202+ 'type_for_register',
1203+ 'reconcile',
1204+ 'parent_id.code',
1205+ 'is_not_hq_correctible',
1206+ 'shrink_entries_for_hq',
1207+ 'currency_revaluation',
1208+ ],
1209+ 'required_field_list': [
1210+ 'user_type.code',
1211+ 'activation_date',
1212+ 'code',
1213+ 'type',
1214+ 'name',
1215+ 'type_for_register',
1216+ ],
1217+ },
1218+ 'gl_journals': {
1219+ 'header_list': [
1220+ 'code',
1221+ 'currency.name',
1222+ 'default_credit_account_id.code',
1223+ 'default_debit_account_id.code',
1224+ 'name',
1225+ 'type',
1226+ 'analytic_journal_id.code',
1227+ ],
1228+ 'required_field_list': [
1229+ 'code',
1230+ 'name',
1231+ 'type',
1232+ 'analytic_journal_id.code',
1233+ ],
1234+ },
1235+ 'analytic_accounts': {
1236+ 'header_list': [
1237+ 'name',
1238+ 'code',
1239+ 'category',
1240+ 'parent_id.code',
1241+ 'type',
1242+ 'date_start',
1243+ ],
1244+ 'required_field_list': [
1245+ 'name',
1246+ 'code',
1247+ 'category',
1248+ 'parent_id.code',
1249+ 'date_start',
1250+ ],
1251+ },
1252+ 'analytic_journals': {
1253+ 'header_list': [
1254+ 'active',
1255+ 'code',
1256+ 'name',
1257+ 'type',
1258+ ],
1259+ 'required_field_list': [
1260+ 'code',
1261+ 'name',
1262+ 'type',
1263+ ],
1264+ },
1265+ 'employees': {
1266+ 'header_list': [
1267+ 'name',
1268+ 'identification_id',
1269+ 'active',
1270+ ],
1271+ 'required_field_list': [
1272+ 'name',
1273+ 'identification_id',
1274+ ],
1275+ },
1276+ 'hq_entries': {
1277+ 'header_list': [
1278+ 'name',
1279+ 'ref',
1280+ 'document_date',
1281+ 'date',
1282+ 'account_id',
1283+ 'partner_txt',
1284+ 'amount',
1285+ 'currency_id.name',
1286+ 'destination_id',
1287+ 'cost_center_id',
1288+ 'analytic_id',
1289+ 'free_1_id',
1290+ 'free_2_id',
1291+ ],
1292+ 'required_field_list': [
1293+ 'name',
1294+ 'account_id',
1295+ 'currency_id.name',
1296+ 'destination_id',
1297+ 'analytic_id',
1298+ ],
1299+ },
1300+ 'currency_rate': {
1301+ 'header_list': [
1302+ 'name',
1303+ 'rate',
1304+ 'currency_id.name',
1305+ ],
1306+ 'required_field_list': [
1307+ 'name',
1308+ 'rate',
1309+ 'currency_id.name',
1310+ ],
1311+ },
1312+
1313+
1314+ # NON FUNCTIONNAL
1315+ 'user_groups': {
1316+ 'header_list': [
1317+ 'name',
1318+ ],
1319+ 'required_field_list': [
1320+ 'name',
1321+ ],
1322+ },
1323+ 'user_access': {
1324+ 'header_list': [
1325+ ],
1326+ 'required_field_list': [
1327+ ],
1328+ 'hide_export': True,
1329+ },
1330+ 'record_rules': {
1331+ 'header_list': [
1332+ 'model_id.model',
1333+ 'name',
1334+ 'global',
1335+ 'domain_force',
1336+ 'perm_read',
1337+ 'perm_write',
1338+ 'perm_create',
1339+ 'perm_unlink',
1340+ ],
1341+ 'required_field_list': [
1342+ 'model_id.model',
1343+ 'name',
1344+ ],
1345+ },
1346+ 'access_control_list': {
1347+ 'header_list': [
1348+ 'name',
1349+ 'model_id.model',
1350+ 'group_id.name',
1351+ 'perm_read',
1352+ 'perm_write',
1353+ 'perm_create',
1354+ 'perm_unlink',
1355+ ],
1356+ 'required_field_list': [
1357+ 'name',
1358+ 'model_id.model',
1359+ ],
1360+ },
1361+ 'field_access_rules': {
1362+ 'header_list': [
1363+ 'name',
1364+ 'model_id.model',
1365+ 'instance_level',
1366+ 'domain_text',
1367+ 'status',
1368+ ],
1369+ 'required_field_list': [
1370+ 'name',
1371+ 'model_id.model',
1372+ 'instance_level',
1373+ ],
1374+ },
1375+ 'field_access_rule_lines': {
1376+ 'header_list': [
1377+ 'field_access_rule.name',
1378+ 'field_access_rule_model_id',
1379+ 'field.name',
1380+ 'field_name',
1381+ 'write_access',
1382+ 'value_not_synchronized_on_create',
1383+ 'value_not_synchronized_on_write',
1384+ ],
1385+ 'required_field_list': [
1386+ 'field_access_rule',
1387+ 'field',
1388+ ],
1389+ },
1390+ 'button_access_rules': {
1391+ 'header_list': [
1392+ 'model_id.model',
1393+ 'view_id.name',
1394+ 'label',
1395+ 'name',
1396+ 'group_names',
1397+ 'type',
1398+ ],
1399+ 'required_field_list': [
1400+ 'model_id.model',
1401+ 'view_id.name',
1402+ 'name',
1403+ ],
1404+ },
1405+ 'window_actions': {
1406+ 'header_list': [
1407+ 'name',
1408+ 'res_model',
1409+ 'view_type',
1410+ 'view_id.name',
1411+ 'domain',
1412+ 'groups_id',
1413+ ],
1414+ 'required_field_list': [
1415+ 'name',
1416+ 'res_model',
1417+ 'view_type',
1418+ ],
1419+ },
1420+}
1421+
1422+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1423
1424=== added file 'bin/addons/msf_doc_import/report/export_generic.mako'
1425--- bin/addons/msf_doc_import/report/export_generic.mako 1970-01-01 00:00:00 +0000
1426+++ bin/addons/msf_doc_import/report/export_generic.mako 2017-09-12 08:08:04 +0000
1427@@ -0,0 +1,137 @@
1428+<?xml version="1.0"?>
1429+<?mso-application progid="Excel.Sheet"?>
1430+<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
1431+ xmlns:o="urn:schemas-microsoft-com:office:office"
1432+ xmlns:x="urn:schemas-microsoft-com:office:excel"
1433+ xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
1434+ xmlns:html="http://www.w3.org/TR/REC-html40">
1435+
1436+ <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
1437+ <Author>MSFUser</Author>
1438+ <LastAuthor>MSFUser</LastAuthor>
1439+ <Created>2012-06-18T15:46:09Z</Created>
1440+ <Company>Medecins Sans Frontieres</Company>
1441+ <Version>11.9999</Version>
1442+ </DocumentProperties>
1443+
1444+ <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
1445+ <WindowHeight>13170</WindowHeight>
1446+ <WindowWidth>19020</WindowWidth>
1447+ <WindowTopX>120</WindowTopX>
1448+ <WindowTopY>60</WindowTopY>
1449+ <ProtectStructure>False</ProtectStructure>
1450+ <ProtectWindows>False</ProtectWindows>
1451+ </ExcelWorkbook>
1452+
1453+ <Styles>
1454+ <Style ss:ID="header">
1455+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1456+ <Interior ss:Color="#ffcc99" ss:Pattern="Solid"/>
1457+ <Font ss:Bold="1" ss:Color="#000000" />
1458+ <Borders>
1459+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
1460+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
1461+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
1462+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
1463+ </Borders>
1464+ <Protection />
1465+ </Style>
1466+ <Style ss:ID="String">
1467+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1468+ <Borders>
1469+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
1470+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
1471+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
1472+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
1473+ </Borders>
1474+ <Protection ss:Protected="0" />
1475+ </Style>
1476+ <Style ss:ID="Boolean">
1477+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1478+ <Borders>
1479+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
1480+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
1481+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
1482+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
1483+ </Borders>
1484+ <Protection ss:Protected="0" />
1485+ </Style>
1486+ <Style ss:ID="Float">
1487+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1488+ <Borders>
1489+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
1490+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
1491+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
1492+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
1493+ </Borders>
1494+ <NumberFormat ss:Format="Fixed" />
1495+ <Protection ss:Protected="0" />
1496+ </Style>
1497+ <Style ss:ID="Number">
1498+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1499+ <Borders>
1500+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
1501+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
1502+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
1503+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
1504+ </Borders>
1505+ <NumberFormat ss:Format="Fixed" />
1506+ <Protection ss:Protected="0" />
1507+ </Style>
1508+ <Style ss:ID="DateTime">
1509+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1510+ <Borders>
1511+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>
1512+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>
1513+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>
1514+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>
1515+ </Borders>
1516+ <NumberFormat ss:Format="Short Date" />
1517+ <Protection ss:Protected="0" />
1518+ </Style>
1519+ </Styles>
1520+
1521+ <ss:Worksheet ss:Name="${data.get('model_name', _('Sheet 1'))|x}" ss:Protected="0">
1522+
1523+ <Table x:FullColumns="1" x:FullRows="1">
1524+
1525+ <% rows = getRows(data['model'], data['fields'], data.get('nb_lines'), data.get('domain'), data.get('template_only', False), data['context']) %>
1526+ <% headers = getHeaders(data['model'], data['fields'], rows, data['context']) %>
1527+ % for col in headers:
1528+ <Column ss:AutoFitWidth="1" ss:Width="${col[2] or 70|x}" ss:StyleID="${col[1]|x}" />
1529+ % endfor
1530+
1531+ <Row>
1532+ % for col in headers:
1533+ <Cell ss:StyleID="header">
1534+ <Data ss:Type="String">${col[0]|x}</Data>
1535+ </Cell>
1536+ % endfor
1537+ </Row>
1538+
1539+ % if not data.get('template_only', False):
1540+ % for row in rows:
1541+ <Row>
1542+ % for index, cell in enumerate(row):
1543+ <Cell ss:StyleID="${headers[index][1]|x}">
1544+ % if headers[index][1] == 'String' and not cell:
1545+ <Data ss:Type="String"></Data>
1546+ % else:
1547+ <Data ss:Type="String">${cell|x}</Data>
1548+ % endif
1549+ </Cell>
1550+ % endfor
1551+ </Row>
1552+ % endfor
1553+ % endif
1554+ </Table>
1555+
1556+ <x:WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
1557+ <ProtectScenarios>False</ProtectScenarios>
1558+ <EnableSelection>UnlockedCells</EnableSelection>
1559+ <AllowInsertRows />
1560+ </x:WorksheetOptions>
1561+
1562+ </ss:Worksheet>
1563+
1564+</Workbook>
1565
1566=== modified file 'bin/addons/msf_doc_import/report/import_generic_template.mako'
1567--- bin/addons/msf_doc_import/report/import_generic_template.mako 2016-08-15 11:49:05 +0000
1568+++ bin/addons/msf_doc_import/report/import_generic_template.mako 2017-09-12 08:08:04 +0000
1569@@ -46,6 +46,27 @@
1570 </Borders>
1571 <Protection ss:Protected="0" />
1572 </Style>
1573+ <Style ss:ID="Boolean">
1574+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1575+ <Borders>
1576+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
1577+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
1578+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
1579+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
1580+ </Borders>
1581+ <Protection ss:Protected="0" />
1582+ </Style>
1583+ <Style ss:ID="Float">
1584+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1585+ <Borders>
1586+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
1587+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
1588+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
1589+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
1590+ </Borders>
1591+ <NumberFormat ss:Format="Fixed" />
1592+ <Protection ss:Protected="0" />
1593+ </Style>
1594 <Style ss:ID="Number">
1595 <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
1596 <Borders>
1597
1598=== modified file 'bin/addons/msf_doc_import/report/import_generic_template.py'
1599--- bin/addons/msf_doc_import/report/import_generic_template.py 2016-07-27 09:38:38 +0000
1600+++ bin/addons/msf_doc_import/report/import_generic_template.py 2017-09-12 08:08:04 +0000
1601@@ -19,12 +19,64 @@
1602 #
1603 ##############################################################################
1604
1605+from report import report_sxw
1606 from report_webkit.webkit_report import XlsWebKitParser
1607
1608+
1609 XlsWebKitParser(
1610 'report.wizard.import.generic.template',
1611 'abstract.wizard.import',
1612 'addons/msf_doc_import/report/import_generic_template.mako',
1613 )
1614
1615+
1616+class report_generic_export_parser(report_sxw.rml_parse):
1617+
1618+ def __init__(self, cr, uid, name, context=None):
1619+ super(report_generic_export_parser, self).__init__(cr, uid, name, context=context)
1620+ self.localcontext.update({
1621+ 'getHeaders': self.getHeaders,
1622+ 'getRows': self.getRows,
1623+ })
1624+ return
1625+
1626+ def getHeaders(self, model, field_list, rows, context=None):
1627+ '''
1628+ get the column names of the table. Set the type of the column and the
1629+ size of it.
1630+ '''
1631+ import_export_obj = self.pool.get('msf.import.export')
1632+ return import_export_obj._get_headers(self.cr, self.uid, model,
1633+ selection=None, field_list=field_list, rows=rows, context=context)
1634+
1635+ def getRows(self, model, fields, nb_lines=None, domain=None,
1636+ template_only=False, context=None):
1637+ """
1638+ Return list of lines from given generic export
1639+ """
1640+ if context is None:
1641+ context={}
1642+ if template_only:
1643+ return []
1644+ if not domain:
1645+ domain = []
1646+ rows = []
1647+ counter = 0
1648+ chunk_size = 100
1649+ model_obj = self.pool.get(model)
1650+ ids = model_obj.search(self.cr, self.uid, domain, limit=nb_lines)
1651+ fields = [x.replace('.', '/') for x in fields]
1652+ for i in range(0, len(ids), chunk_size):
1653+ ids_chunk = ids[i:i + chunk_size]
1654+ counter += len(ids_chunk)
1655+ context['translate_selection_field'] = True
1656+ rows.extend(model_obj.export_data(self.cr, self.uid, ids_chunk, fields, context=context)['datas'])
1657+ return rows
1658+
1659+XlsWebKitParser(
1660+ 'report.wizard.export.generic',
1661+ 'msf.import.export',
1662+ 'addons/msf_doc_import/report/export_generic.mako',
1663+ parser=report_generic_export_parser,
1664+)
1665 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1666
1667=== added file 'bin/addons/msf_doc_import/view/msf_import_export_view.xml'
1668--- bin/addons/msf_doc_import/view/msf_import_export_view.xml 1970-01-01 00:00:00 +0000
1669+++ bin/addons/msf_doc_import/view/msf_import_export_view.xml 2017-09-12 08:08:04 +0000
1670@@ -0,0 +1,96 @@
1671+<?xml version="1.0" encoding="utf-8" ?>
1672+<openerp>
1673+<data>
1674+
1675+ <record id="msf_import_export_view" model="ir.ui.view">
1676+ <field name="name">msf.import.export.view</field>
1677+ <field name="model">msf.import.export</field>
1678+ <field name="type">form</field>
1679+ <field name="arch" type="xml">
1680+ <form string="Import / Export">
1681+ <group>
1682+ <field name="display_file_import" invisible="1" />
1683+ <field name="display_file_export" invisible="1" />
1684+ <field name='model_list_selection' on_change="domain_type_change(model_list_selection)" />
1685+ </group>
1686+ <group col="4" colspan="4">
1687+ <field name="hide_download_3_entries" invisible="1" />
1688+ <field name="hide_download_all_entries" invisible="1" />
1689+ <group colspan="2" col="2" name="file_import" attrs="{'invisible':[('display_file_import', '=', False)]}">
1690+ <separator string="File Import" colspan="2"/>
1691+ <field name="display_test_import_button" invisible="1" />
1692+ <field name="import_file" colspan="4" on_change="file_change(import_file)"/>
1693+ <button name="test_import" string="Test file" type="object" icon="gtk-ok" colspan="4" attrs="{'invisible':[('display_test_import_button', '=', False)]}" />
1694+ <button name="import_xml" string="Run import" type="object" icon="gtk-execute" colspan="4" attrs="{'invisible': [('state', '!=', 'draft')]}" />
1695+ <separator colspan="4" string="Information" />
1696+ <field name="info_message" colspan="4" nolabel="1" />
1697+ </group>
1698+ <group colspan="2" col="2" name="file_export">
1699+ <separator string="File Export" colspan="2"/>
1700+ <group attrs="{'invisible':[('display_file_export', '=', False)]}">
1701+ <button name="download_template_file" string="Export empty template" icon="gtk-save" help="Download template file" type="object" />
1702+ <button name="download_3_entries_file" string="Export first 3 entries" type="object" icon="gtk-save" colspan="4" attrs="{'invisible':[('hide_download_3_entries', '=', True)]}"/>
1703+ <button name="download_all_entries_file" string="Export all data" type="object" icon="gtk-save" colspan="4" attrs="{'invisible':[('hide_download_all_entries', '=', True)]}"/>
1704+ </group>
1705+ </group>
1706+ <group colspan="4" attrs="{'invisible': [('show_warning', '=', False)]}">
1707+ <separator colspan="4" string="Warning messages" />
1708+ <field name="warning_message" nolabel="1" colspan="4" widget="full_text"/>
1709+ </group>
1710+
1711+ <group colspan="4" attrs="{'invisible': [('show_error', '=', False)]}">
1712+ <separator colspan="4" string="Error messages" />
1713+ <field name="error_message" nolabel="1" colspan="4" widget="full_text"/>
1714+ </group>
1715+ </group>
1716+ </form>
1717+ </field>
1718+ </record>
1719+
1720+
1721+ <record id="msf_import_export_supply_action" model="ir.actions.act_window">
1722+ <field name="name">Supply</field>
1723+ <field name="res_model">msf.import.export</field>
1724+ <field name="view_type">form</field>
1725+ <field name="view_mode">form</field>
1726+ <field name="target">current</field>
1727+ <field name="context">{'domain_type': 'supply'}</field>
1728+ </record>
1729+
1730+ <record id="msf_import_export_finance_action" model="ir.actions.act_window">
1731+ <field name="name">Finance</field>
1732+ <field name="res_model">msf.import.export</field>
1733+ <field name="view_type">form</field>
1734+ <field name="view_mode">form</field>
1735+ <field name="target">current</field>
1736+ <field name="context">{'domain_type': 'finance'}</field>
1737+ </record>
1738+
1739+ <record id="msf_import_export_non_functional_action" model="ir.actions.act_window">
1740+ <field name="name">Non Functional</field>
1741+ <field name="res_model">msf.import.export</field>
1742+ <field name="view_type">form</field>
1743+ <field name="view_mode">form</field>
1744+ <field name="target">current</field>
1745+ <field name="context">{'domain_type': 'non_functionnal'}</field>
1746+ </record>
1747+
1748+ <menuitem id="msf_import_export_menu"
1749+ name="Import / Export"
1750+ parent="object_query.menu_preferences" />
1751+
1752+ <menuitem id="msf_import_export_supply_menu"
1753+ parent="msf_import_export_menu"
1754+ action="msf_import_export_supply_action" />
1755+
1756+ <menuitem id="msf_import_export_finance_menu"
1757+ parent="msf_import_export_menu"
1758+ action="msf_import_export_finance_action" />
1759+
1760+ <menuitem id="msf_import_export_non_functional_menu"
1761+ parent="msf_import_export_menu"
1762+ action="msf_import_export_non_functional_action" />
1763+
1764+
1765+</data>
1766+</openerp>
1767
1768=== modified file 'bin/addons/msf_doc_import/wizard/abstract_wizard_import.py'
1769--- bin/addons/msf_doc_import/wizard/abstract_wizard_import.py 2017-03-20 09:49:38 +0000
1770+++ bin/addons/msf_doc_import/wizard/abstract_wizard_import.py 2017-09-12 08:08:04 +0000
1771@@ -39,7 +39,7 @@
1772 """
1773 Class used to export Header template.
1774 """
1775- type_ok = ['String', 'Number', 'DateTime']
1776+ type_ok = ['String', 'Number', 'DateTime', 'Boolean', 'Float']
1777
1778 def __new__(cls, name, ftype='String', size=70, tech_name=None, required=False):
1779 """
1780@@ -71,12 +71,12 @@
1781 :return: A datetime instance or False
1782 """
1783 # US:2527: accept only one format, reject other
1784- date_format = [
1785+ accepted_date_format = [
1786 '%d/%m/%Y',
1787 ]
1788
1789 d = False
1790- for dformat in date_format:
1791+ for dformat in accepted_date_format:
1792 try:
1793 d = DateTime.strptime(date_value, dformat)
1794 d = d.strftime('%Y-%m-%d %H:%M:%S')
1795@@ -130,9 +130,22 @@
1796 return (0, value, None)
1797 else:
1798 try:
1799+ if isinstance(value, basestring):
1800+ value = value.rstrip().replace(',', '.')
1801 return (0, float(value), None)
1802 except Exception as e:
1803 return (-1, value, e)
1804+ elif header[1] == 'Boolean':
1805+ if value.upper() in ('T', 'TRUE', '1'):
1806+ value = True
1807+ else:
1808+ value = False
1809+ elif header[1] == 'Number':
1810+ if vtype =='int':
1811+ try:
1812+ return (0, int(value), None)
1813+ except Exception as e:
1814+ return (-1, value, e)
1815
1816 return (0, value, None)
1817
1818
1819=== modified file 'bin/addons/msf_profile/i18n/fr_MF.po'
1820--- bin/addons/msf_profile/i18n/fr_MF.po 2017-09-08 15:57:28 +0000
1821+++ bin/addons/msf_profile/i18n/fr_MF.po 2017-09-12 08:08:04 +0000
1822@@ -4544,13 +4544,14 @@
1823 msgid "Contact Titles"
1824 msgstr "Titre/Position Contact"
1825
1826-#. module: msf_button_access_rights
1827+#. modules: msf_button_access_rights, msf_doc_import
1828 #: model:ir.actions.act_window,name:msf_button_access_rights.button_access_rule_list
1829 #: model:ir.ui.menu,name:msf_button_access_rights.msf_button_access_rules
1830 #: view:ir.ui.view:0
1831 #: field:ir.ui.view,button_access_rules_ref:0
1832+#: code:addons/msf_doc_import/msf_import_export_conf.py:124
1833 msgid "Button Access Rules"
1834-msgstr "Button Access Rules"
1835+msgstr "Règles d'Accès de bouton"
1836
1837 #. module: stock
1838 #: code:addons/stock/stock.py:1091
1839@@ -7005,11 +7006,6 @@
1840 msgid "MSF Codification"
1841 msgstr "Codification MSF"
1842
1843-#. module: product_list
1844-#: view:product.list.line:0
1845-msgid "Products"
1846-msgstr "Products"
1847-
1848 #. module: base_setup
1849 #: view:base.setup.company:0
1850 msgid "Your company information will be used to personalize documents issued with OpenERP such as invoices, sales orders and much more."
1851@@ -13296,12 +13292,6 @@
1852 msgid "Destinations"
1853 msgstr "Destinations"
1854
1855-#. module: import_data
1856-#: selection:import_category,object:0
1857-#: selection:import_nomenclature,object:0
1858-msgid "Product Nomenclature"
1859-msgstr "Product Nomenclature"
1860-
1861 #. module: analytic_distribution
1862 #: code:addons/analytic_distribution/account_commitment.py:166
1863 #, python-format
1864@@ -15965,6 +15955,47 @@
1865 msgid "New Zealand"
1866 msgstr "Nouvelle-Zélande"
1867
1868+#. modules: msf_doc_import, msf_supply_doc_export
1869+#: code:addons/msf_doc_import/wizard/__init__.py:68
1870+#: code:addons/msf_doc_import/wizard/__init__.py:73
1871+#: code:addons/msf_doc_import/wizard/__init__.py:78
1872+#: code:addons/msf_doc_import/wizard/wizard_in_simulation_screen.py:65
1873+#: report:addons/msf_supply_doc_export/report/report_real_composition_kit_xls.mako:71
1874+#, python-format
1875+msgid "Expiry Date"
1876+msgstr "Date d'expiration"
1877+
1878+#. modules: account, msf_outgoing, register_accounting, account_override, purchase_compare_rfq, msf_doc_import, return_claim, analytic_distribution
1879+#: code:addons/account/report/account_general_ledger.py:550
1880+#: view:account.chart:0
1881+#: field:account.chart,currency_id:0
1882+#: view:account.analytic.chart:0
1883+#: field:account.analytic.chart,currency_id:0
1884+#: code:addons/msf_doc_import/wizard/wizard_in_simulation_screen.py:63
1885+#: code:addons/msf_doc_import/wizard/wizard_po_simulation_screen.py:70
1886+#: field:wizard.import.po.simulation.screen,in_currency:0
1887+#: field:wizard.import.po.simulation.screen.line,imp_currency:0
1888+#: field:wizard.import.po.simulation.screen.line,in_currency:0
1889+#: field:wizard.simu.import.po.line,currency_id:0
1890+#: field:wizard.simu.import.po.line,initial_currency:0
1891+#: field:create.picking.move.processor,currency:0
1892+#: field:internal.move.processor,currency:0
1893+#: field:outgoing.delivery.move.processor,currency:0
1894+#: field:ppl.move.processor,currency:0
1895+#: field:return.ppl.move.processor,currency:0
1896+#: field:stock.move.in.processor,currency:0
1897+#: field:stock.move.processor,currency:0
1898+#: field:validate.move.processor,currency:0
1899+#: field:wizard.compare.rfq,currency_id:0
1900+#: field:account.direct.invoice.wizard,currency_id:0
1901+#: field:wizard.account.invoice,fake_currency_id:0
1902+#: field:wizard.account.invoice,virtual_currency_id:0
1903+#: field:claim.product.line,price_currency_claim_product_line:0
1904+#: field:claim.product.line,price_unit_claim_product_line:0
1905+#, python-format
1906+msgid "Currency"
1907+msgstr "Devise"
1908+
1909 #. module: sale
1910 #: help:sale.order.line,delay:0
1911 msgid "Number of days between the order confirmation the shipping of the products to the customer"
1912@@ -17377,6 +17408,7 @@
1913
1914 #. module: msf_doc_import
1915 #: view:wizard.import.batch:0
1916+#: view:msf.import.export:0
1917 msgid "Warning messages"
1918 msgstr "Messages d'avertissement"
1919
1920@@ -20661,9 +20693,11 @@
1921 msgid "IN update OUT"
1922 msgstr "IN update OUT"
1923
1924-#. module: import_data
1925+#. modules: import_data, msf_doc_import
1926 #: code:addons/import_data/import_data.py:317
1927 #: code:addons/import_data/import_data.py:356
1928+#: code:addons/msf_doc_import/msf_import_export.py:499
1929+#: code:addons/msf_doc_import/msf_import_export.py:528
1930 #, python-format
1931 msgid "%s does not exist"
1932 msgstr "%s n'existe pas"
1933@@ -24759,11 +24793,12 @@
1934 msgid "This wizard will validate all journal entries of a particular journal and period. Once journal entries are validated, you can not update them anymore."
1935 msgstr "Cet assistant validera toutes les écritures comptables pour un journal particulier et une période. Une fois validées, les écritures comptables ne peuvent plus être modifiées."
1936
1937-#. module: msf_field_access_rights
1938+#. modules: msf_field_access_rights, msf_doc_import
1939 #: model:ir.actions.act_window,name:msf_field_access_rights.field_access_rules_list
1940 #: model:ir.ui.menu,name:msf_field_access_rights.msf_field_access_rules
1941+#: code:addons/msf_doc_import/msf_import_export_conf.py:114
1942 msgid "Field Access Rules"
1943-msgstr "Field Access Rules"
1944+msgstr "Règles d'Accès au Champs"
1945
1946 #. modules: account, msf_outgoing, finance, sync_client, register_accounting, account_override, sourcing, sync_so, res_currency_functional, analytic_distribution
1947 #: code:addons/account/report/account_general_ledger.py:252
1948@@ -25725,9 +25760,10 @@
1949 msgid "No Period found on Invoice!"
1950 msgstr "Pas de Période indiquée sur la Facture!"
1951
1952-#. module: supplier_catalogue
1953+#. modules: supplier_catalogue, msf_doc_import
1954 #: model:ir.actions.act_window,name:supplier_catalogue.action_supplier_catalogue_line_list
1955 #: view:supplier.catalogue.line:0
1956+#: code:addons/msf_doc_import/msf_import_export_conf.py:53
1957 msgid "Supplier catalogue lines"
1958 msgstr "Lignes Catalogue Fournisseur"
1959
1960@@ -25857,6 +25893,7 @@
1961
1962 #. module: msf_doc_import
1963 #: view:wizard.import.batch:0
1964+#: view:msf.import.export:0
1965 msgid "Run import"
1966 msgstr "Démarrer l'import"
1967
1968@@ -29743,7 +29780,13 @@
1969 msgid "Total amount this customer owes you."
1970 msgstr "Montant Total Dû par ce Client."
1971
1972-#. modules: tender_flow, msf_partner, account, product, base, useability_dashboard_and_menu
1973+#. modules: consumption_calculation, stock_override
1974+#: report:addons/consumption_calculation/report/report_monthly_consumption_xls.mako:70
1975+#: field:export.report.stock.move,name:0
1976+msgid "Generated on"
1977+msgstr "Generated on"
1978+
1979+#. modules: tender_flow, msf_partner, account, product, base, useability_dashboard_and_menu, msf_doc_import
1980 #: model:ir.ui.menu,name:account.menu_account_supplier
1981 #: model:ir.ui.menu,name:account.menu_finance_payables
1982 #: model:ir.actions.act_window,name:base.action_partner_supplier_form
1983@@ -29755,6 +29798,7 @@
1984 #: view:tender:0
1985 #: field:tender,supplier_ids:0
1986 #: model:ir.ui.menu,name:useability_dashboard_and_menu.menu_supplier
1987+#: code:addons/msf_doc_import/msf_import_export_conf.py:42
1988 msgid "Suppliers"
1989 msgstr "Fournisseurs"
1990
1991@@ -30275,11 +30319,6 @@
1992 msgid "Line %s. No info about given account: %s"
1993 msgstr "Line %s. No info about given account: %s"
1994
1995-#. module: account_hq_entries
1996-#: model:ir.module.module,shortdesc:account_hq_entries.module_meta_information
1997-msgid "HQ Entries"
1998-msgstr "HQ Entries"
1999-
2000 #. module: msf_budget
2001 #: view:wizard.budget.summary.export:0
2002 msgid "Budget Summary PDF Export"
2003@@ -30894,6 +30933,7 @@
2004
2005 #. module: msf_doc_import
2006 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:308
2007+#: code:addons/msf_doc_import/msf_import_export.py:688
2008 #, python-format
2009 msgid "(%s line(s) with warning - see warning messages below)"
2010 msgstr "(%s ligne(s) avec des avertissements - voir les avertissements ci-dessous)"
2011@@ -32587,6 +32627,7 @@
2012
2013 #. module: msf_doc_import
2014 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:313
2015+#: code:addons/msf_doc_import/msf_import_export.py:693
2016 #, python-format
2017 msgid "no data will be imported until all the error messages are corrected"
2018 msgstr "aucune donnée ne sera importée tant que toutes les erreurs ne seront pas corrigées"
2019@@ -35506,6 +35547,7 @@
2020
2021 #. module: msf_doc_import
2022 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:298
2023+#: code:addons/msf_doc_import/msf_import_export.py:678
2024 #, python-format
2025 msgid "Processing of file completed in %s second(s)!\n"
2026 "- Total lines to import: %s\n"
2027@@ -36767,8 +36809,11 @@
2028 msgid "Move state"
2029 msgstr "Statut de la transaction "
2030
2031-#. module: procurement_auto
2032+#. modules: procurement_auto, procurement, msf_doc_import
2033 #: field:stock.warehouse.automatic.supply.line,supply_id:0
2034+#: field:stock.warehouse.orderpoint.line,supply_id:0
2035+#: model:ir.actions.act_window,name:msf_doc_import.msf_import_export_supply_action
2036+#: model:ir.ui.menu,name:msf_doc_import.msf_import_export_supply_menu
2037 msgid "Supply"
2038 msgstr "Approvisionnement"
2039
2040@@ -40027,12 +40072,14 @@
2041 msgid "DP execute"
2042 msgstr "DP execute"
2043
2044-#. modules: msf_instance, sync_so, account_hq_entries
2045+#. modules: msf_instance, sync_so, account_hq_entries, account_hq_entries, msf_doc_import
2046 #: model:ir.actions.act_window,name:account_hq_entries.action_hq_entries_tree
2047 #: model:ir.model,name:account_hq_entries.model_hq_entries
2048 #: model:ir.ui.menu,name:account_hq_entries.menu_hq_entries
2049 #: view:res.company:0
2050 #: model:ir.model,name:sync_so.model_hq_entries
2051+#: model:ir.module.module,shortdesc:account_hq_entries.module_meta_information
2052+#: code:addons/msf_doc_import/msf_import_export_conf.py:81
2053 msgid "HQ Entries"
2054 msgstr "Ecritures HQ"
2055
2056@@ -42744,6 +42791,7 @@
2057
2058 #. module: msf_doc_import
2059 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:306
2060+#: code:addons/msf_doc_import/msf_import_export.py:686
2061 #, python-format
2062 msgid "imported"
2063 msgstr "importées"
2064@@ -42986,6 +43034,7 @@
2065
2066 #. module: msf_doc_import
2067 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:306
2068+#: code:addons/msf_doc_import/msf_import_export.py:686
2069 #, python-format
2070 msgid "without errors"
2071 msgstr "sans erreurs"
2072@@ -48145,7 +48194,8 @@
2073 msgid "Report can not be edited due to missing FX rates in specific currency table %s"
2074 msgstr "Report can not be edited due to missing FX rates in specific currency table %s"
2075
2076-#. module: base
2077+#. modules: base, msf_doc_import
2078+#: code:addons/msf_doc_import/msf_import_export_conf.py:86
2079 #: model:ir.actions.act_window,name:base.ir_access_act
2080 #: model:ir.ui.menu,name:base.menu_ir_access_act
2081 msgid "Access Controls List"
2082@@ -50484,7 +50534,7 @@
2083 msgid "Followup lines"
2084 msgstr "Suivi des Lignes"
2085
2086-#. modules: msf_budget, account, financing_contract, analytic_distribution
2087+#. modules: msf_budget, account, financing_contract, analytic_distribution, msf_doc_import
2088 #: view:account.analytic.account:0
2089 #: model:ir.ui.menu,name:account.account_analytic_def_account
2090 #: view:account.analytic.account:0
2091@@ -50492,6 +50542,7 @@
2092 #: model:ir.ui.menu,name:financing_contract.menu_action_account_analytic_account_form
2093 #: view:account.analytic.account:0
2094 #: model:ir.ui.menu,name:msf_budget.menu_action_account_analytic_account_budget_form
2095+#: code:addons/msf_doc_import/msf_import_export_conf.py:66
2096 msgid "Analytic Accounts"
2097 msgstr "Comptes Analytiques"
2098
2099@@ -50610,7 +50661,7 @@
2100 msgid "Read Access"
2101 msgstr "Accès Lecture"
2102
2103-#. modules: product_nomenclature, import_data, product_asset, kit
2104+#. modules: product_nomenclature, import_data, product_asset, kit, msf_doc_import
2105 #: selection:import_data,object:0
2106 #: selection:import_product,object:0
2107 #: selection:update_product,object:0
2108@@ -50618,6 +50669,9 @@
2109 #: field:product.asset,nomenclature_description:0
2110 #: model:ir.model,name:product_nomenclature.model_product_nomenclature
2111 #: view:product.nomenclature:0
2112+#: selection:import_category,object:0
2113+#: selection:import_nomenclature,object:0
2114+#: code:addons/msf_doc_import/msf_import_export_conf.py:32
2115 msgid "Product Nomenclature"
2116 msgstr "Nomenclature du Produit"
2117
2118@@ -51151,7 +51205,7 @@
2119 #: code:addons/msf_outgoing/wizard/validate_picking_processor.py:75
2120 #, python-format
2121 msgid "Line %s: %s"
2122-msgstr "Ligne %s: %s"
2123+msgstr "Ligne %s : %s"
2124
2125 #. module: account_override
2126 #: help:account.move.line,journal_type:0
2127@@ -52986,11 +53040,6 @@
2128 msgid "Included Fields"
2129 msgstr "Champs Inclus"
2130
2131-#. module: kit
2132-#: view:kit.mass.import:0
2133-msgid "Error messages"
2134-msgstr "Error messages"
2135-
2136 #. module: msf_partner
2137 #: view:res.partner:0
2138 msgid "Customer LT"
2139@@ -56414,13 +56463,14 @@
2140 msgid "Choose Fiscal Year"
2141 msgstr "Choisir l'Exercice Comptable "
2142
2143-#. module: msf_field_access_rights
2144+#. modules: msf_field_access_rights, msf_doc_import
2145 #: model:ir.actions.act_window,name:msf_field_access_rights.field_access_rule_line_list
2146 #: model:ir.ui.menu,name:msf_field_access_rights.field_access_rule_line_list_menu
2147 #: view:msf_field_access_rights.field_access_rule:0
2148 #: field:msf_field_access_rights.field_access_rule,field_access_rule_line_ids:0
2149+#: code:addons/msf_doc_import/msf_import_export_conf.py:119
2150 msgid "Field Access Rule Lines"
2151-msgstr "Field Access Rule Lines"
2152+msgstr "Lignes de Règle d'Accès au Champs"
2153
2154 #. module: analytic_distribution
2155 #: field:analytic.distribution.wizard,fp_line_ids:0
2156@@ -56584,11 +56634,12 @@
2157 msgid "Manually corrected"
2158 msgstr "Manually corrected"
2159
2160-#. modules: account, account_mcdb
2161+#. modules: account, account_mcdb, msf_doc_import
2162 #: view:account.analytic.journal:0
2163 #: model:ir.actions.act_window,name:account.action_account_analytic_journal_form
2164 #: model:ir.ui.menu,name:account.account_def_analytic_journal
2165 #: view:account.mcdb:0
2166+#: code:addons/msf_doc_import/msf_import_export_conf.py:71
2167 msgid "Analytic Journals"
2168 msgstr "Journaux analytiques"
2169
2170@@ -56652,8 +56703,10 @@
2171 msgid "In days"
2172 msgstr "En jours."
2173
2174-#. module: msf_doc_import
2175+#. modules: msf_doc_import, kit
2176+#: view:kit.mass.import:0
2177 #: view:wizard.import.batch:0
2178+#: view:msf.import.export:0
2179 msgid "Error messages"
2180 msgstr "Messages d'erreur"
2181
2182@@ -57560,9 +57613,10 @@
2183 msgid "Action to Trigger"
2184 msgstr "Action à Déclencher"
2185
2186-#. module: base
2187+#. modules: base, msf_doc_import
2188 #: model:ir.actions.act_window,name:base.ir_action_window
2189 #: model:ir.ui.menu,name:base.menu_ir_action_window
2190+#: code:addons/msf_doc_import/msf_import_export_conf.py:129
2191 msgid "Window Actions"
2192 msgstr "Fenêtre Actions"
2193
2194@@ -58838,11 +58892,6 @@
2195 msgid "Specific partner"
2196 msgstr "Partenaire spécifique"
2197
2198-#. module: procurement
2199-#: field:stock.warehouse.orderpoint.line,supply_id:0
2200-msgid "Supply"
2201-msgstr "Supply"
2202-
2203 #. module: sale_override
2204 #: view:sale.order.line:0
2205 msgid "This button shouldn't be use from form view. Please use the red cross on list view."
2206@@ -60862,6 +60911,7 @@
2207 #: selection:wizard.import.batch,state:0
2208 #: view:automated.import.job:0
2209 #: selection:automated.import.job,state:0
2210+#: selection:msf.import.export,state:0
2211 #, python-format
2212 msgid "In progress"
2213 msgstr "En cours"
2214@@ -61119,9 +61169,10 @@
2215 msgid "%y - Year without century [00,99]."
2216 msgstr "%y - Année sans le siècle (00 à 99)."
2217
2218-#. module: base
2219+#. modules: base, msf_doc_import
2220 #: model:ir.actions.act_window,name:base.action_rule
2221 #: model:ir.ui.menu,name:base.menu_action_rule
2222+#: code:addons/msf_doc_import/msf_import_export_conf.py:104
2223 msgid "Record Rules"
2224 msgstr "Règles d´Enregistrement"
2225
2226@@ -61450,6 +61501,7 @@
2227 #: code:addons/sale_override/sale.py:364
2228 #: code:addons/sale_override/sale.py:365
2229 #: code:addons/sale_override/sale.py:366
2230+#: selection:msf.import.export,state:0
2231 #, python-format
2232 msgid "Not started"
2233 msgstr "Non démarré"
2234@@ -61984,6 +62036,32 @@
2235 msgid "Nothing to import"
2236 msgstr "Rien à importer"
2237
2238+#. modules: msf_budget, msf_homere_interface, supplier_catalogue, consumption_calculation, account_hq_entries, msf_doc_import, analytic_distribution, msf_doc_import, register_accounting
2239+#: code:addons/account_hq_entries/wizard/hq_entries_import.py:319
2240+#: code:addons/analytic_distribution/wizard/import_commitment_wizard.py:72
2241+#: code:addons/consumption_calculation/wizard/wizard_import_fmc.py:87
2242+#: code:addons/consumption_calculation/wizard/wizard_import_rac.py:85
2243+#: code:addons/msf_budget/wizard/wizard_budget_import.py:240
2244+#: code:addons/msf_doc_import/composition_kit.py:86
2245+#: code:addons/msf_doc_import/composition_kit.py:181
2246+#: code:addons/msf_doc_import/initial_stock_inventory.py:92
2247+#: code:addons/msf_doc_import/initial_stock_inventory.py:600
2248+#: code:addons/msf_doc_import/stock_cost_reevaluation.py:51
2249+#: code:addons/msf_doc_import/tender.py:98
2250+#: code:addons/msf_doc_import/wizard/wizard_import_product_list.py:88
2251+#: code:addons/msf_doc_import/wizard/wizard_import_supplier_catalogue.py:164
2252+#: code:addons/msf_homere_interface/wizard/hr_payroll_employee_import.py:584
2253+#: code:addons/msf_homere_interface/wizard/hr_payroll_import.py:479
2254+#: code:addons/supplier_catalogue/supplier_catalogue.py:590
2255+#: code:addons/supplier_catalogue/wizard/catalogue_import_lines.py:45
2256+#: code:addons/msf_doc_import/account.py:196
2257+#: code:addons/msf_doc_import/wizard/stock_partial_picking.py:254
2258+#: code:addons/msf_doc_import/wizard/stock_partial_picking.py:785
2259+#: code:addons/register_accounting/wizard/wizard_register_import.py:255
2260+#, python-format
2261+msgid "Nothing to import."
2262+msgstr "Rien à importer"
2263+
2264 #. module: account_mcdb
2265 #: selection:account.mcdb,currency_choice:0
2266 msgid "Booking"
2267@@ -62406,6 +62484,7 @@
2268
2269 #. module: msf_doc_import
2270 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:106
2271+#: code:addons/msf_doc_import/msf_import_export.py:364
2272 #, python-format
2273 msgid "Import in progress, please leave this window open and press the button 'Update' to show the progression of the import. Otherwise, you can continue to use Unifield"
2274 msgstr "Traitement en cours, veuillez laisser cette fenêtre ouverte et cliquez sur le bouton 'Mettre à jour' pour voir la progression de l'import. Sinon, vous pouvez continuer d'utiliser Unifield"
2275@@ -67248,6 +67327,8 @@
2276 #: field:threshold.value,line_ids:0
2277 #: field:threshold.value,product_ids:0
2278 #: view:restrictive.country.setup:0
2279+#: view:product.list.line:0
2280+#: code:addons/msf_doc_import/msf_import_export_conf.py:27
2281 #, python-format
2282 msgid "Products"
2283 msgstr "Produits"
2284@@ -68849,6 +68930,8 @@
2285 #. module: msf_doc_import
2286 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:286
2287 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:292
2288+#: code:addons/msf_doc_import/msf_import_export.py:666
2289+#: code:addons/msf_doc_import/msf_import_export.py:672
2290 #, python-format
2291 msgid "Line %s: %s"
2292 msgstr "Ligne %s : %s"
2293@@ -79938,6 +80021,7 @@
2294 #: field:automated.import.job,state:0
2295 #: field:export.report.inconsistencies,state:0
2296 #: field:export.report.stopped.products,state:0
2297+#: field:msf.import.export,state:0
2298 #: field:wizard.import.invoice.line,state:0
2299 msgid "State"
2300 msgstr "État"
2301@@ -80596,6 +80680,7 @@
2302
2303 #. module: msf_doc_import
2304 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:170
2305+#: code:addons/msf_doc_import/msf_import_export.py:549
2306 #, python-format
2307 msgid "Line seemed empty, so this line was ignored"
2308 msgstr "La ligne semblait vide, donc cette ligne a été ignorée"
2309@@ -80655,7 +80740,7 @@
2310 msgid "Send a test email"
2311 msgstr "Send a test email"
2312
2313-#. modules: tender_flow, product_nomenclature, product_asset, account_override, purchase_allocation_report, register_accounting, product_expiry, procurement_cycle, return_claim, supplier_catalogue, import_data, stock_schedule, unifield_setup, stock_forecast, stock_batch_recall, order_types, msf_doc_import, purchase_followup, product, stock_override, service_purchasing, consumption_calculation, purchase_override, specific_rules, kit, sale_override, product_list, product_manufacturer, procurement_report, threshold_value, purchase, account, msf_outgoing, stock_move_tracking, product_attributes, procurement_auto, sale, transport_mgmt, procurement, sourcing, msf_audittrail, purchase_msf, stock, sync_so
2314+#. modules: tender_flow, product_nomenclature, product_asset, account_override, purchase_allocation_report, register_accounting, product_expiry, procurement_cycle, return_claim, supplier_catalogue, import_data, stock_schedule, unifield_setup, stock_forecast, stock_batch_recall, order_types, msf_doc_import, purchase_followup, product, stock_override, service_purchasing, consumption_calculation, purchase_override, specific_rules, kit, sale_override, product_list, product_manufacturer, procurement_report, threshold_value, purchase, account, msf_outgoing, stock_move_tracking, product_attributes, procurement_auto, sale, transport_mgmt, procurement, sourcing, msf_audittrail, purchase_msf, stock, sync_so, base
2315 #: field:account.analytic.line,product_id:0
2316 #: view:account.entries.report:0
2317 #: field:account.entries.report,product_id:0
2318@@ -80809,6 +80894,47 @@
2319 #: field:threshold.value.line,product_id:0
2320 #: model:ir.model,name:transport_mgmt.model_product_product
2321 #: model:ir.model,name:unifield_setup.model_product_product
2322+#: report:allocation.invoices.report:0
2323+#: selection:res.request,ref_doc1:0
2324+#: selection:res.request,ref_doc2:0
2325+#: field:product.history.consumption.product,product_id:0
2326+#: selection:import_category,object:0
2327+#: selection:import_nomenclature,object:0
2328+#: report:kit.report:0
2329+#: report:addons/msf_doc_import/report/in_simulation_screen_xls_report.mako:149
2330+#: report:addons/msf_doc_import/report/in_simulation_screen_xls_report.mako:158
2331+#: report:addons/msf_doc_import/report/po_simulation_screen_xls_report.mako:230
2332+#: report:addons/msf_doc_import/report/po_simulation_screen_xls_report.mako:241
2333+#: report:po.simulation.screen:0
2334+#: field:product.product.import.line.qty,product_id:0
2335+#: field:wizard.import.in.line.simulation.screen,imp_product_id:0
2336+#: field:wizard.import.in.line.simulation.screen,move_product_id:0
2337+#: field:wizard.import.po.simulation.screen.line,imp_product_id:0
2338+#: field:wizard.import.po.simulation.screen.line,in_product_id:0
2339+#: view:create.picking.move.processor:0
2340+#: field:create.picking.move.processor,product_id:0
2341+#: view:internal.move.processor:0
2342+#: field:internal.move.processor,product_id:0
2343+#: view:outgoing.delivery.move.processor:0
2344+#: field:outgoing.delivery.move.processor,product_id:0
2345+#: view:ppl.move.processor:0
2346+#: field:ppl.move.processor,product_id:0
2347+#: view:return.ppl.move.processor:0
2348+#: field:return.ppl.move.processor,product_id:0
2349+#: view:stock.move.in.processor:0
2350+#: field:stock.move.in.processor,product_id:0
2351+#: view:stock.move.processor:0
2352+#: field:stock.move.processor,product_id:0
2353+#: view:validate.move.processor:0
2354+#: field:validate.move.processor,product_id:0
2355+#: field:stock.warehouse.orderpoint.line,product_id:0
2356+#: view:product.where.used:0
2357+#: field:product.where.used,product_id:0
2358+#: field:standard.price.track.changes,product_id:0
2359+#: field:account.direct.invoice.wizard.line,product_id:0
2360+#: field:unconsistent.stock.report.line,product_id:0
2361+#: view:stock.card.wizard:0
2362+#: field:stock.card.wizard,product_id:0
2363 msgid "Product"
2364 msgstr "Produit"
2365
2366@@ -80902,7 +81028,7 @@
2367 msgid "Select a supplier"
2368 msgstr "Sélectionner un fournisseur"
2369
2370-#. modules: msf_budget, purchase, account, msf_outgoing, account_payment, purchase_override, specific_rules, sale, base, register_accounting, msf_doc_import, return_claim, stock, analytic_distribution, msf_homere_interface
2371+#. modules: msf_budget, purchase, account, msf_outgoing, account_payment, purchase_override, specific_rules, sale, base, register_accounting, msf_doc_import, return_claim, stock, analytic_distribution, delivery_mechanism, sales_followup, sync_client, tender_flow, sale_override, msf_tools, mission_stock, msf_homere_interface
2372 #: selection:account.invoice.report,state:0
2373 #: selection:account.journal.period,state:0
2374 #: selection:account.subscription,state:0
2375@@ -80947,6 +81073,30 @@
2376 #: selection:stock.inventory,state:0
2377 #: view:stock.move:0
2378 #: view:stock.picking:0
2379+#: code:addons/delivery_mechanism/delivery_mechanism.py:1295
2380+#: code:addons/delivery_mechanism/delivery_mechanism.py:1315
2381+#: code:addons/delivery_mechanism/delivery_mechanism.py:1343
2382+#: code:addons/delivery_mechanism/delivery_mechanism.py:1388
2383+#: code:addons/mission_stock/wizard/mission_stock_wizard.py:48
2384+#: code:addons/mission_stock/wizard/mission_stock_wizard.py:56
2385+#: code:addons/msf_outgoing/msf_outgoing.py:3197
2386+#: view:automated.import.job:0
2387+#: selection:automated.import.job,state:0
2388+#: code:addons/sale_override/sale.py:176
2389+#: code:addons/sale_override/sale.py:371
2390+#: code:addons/sale_override/sale.py:372
2391+#: code:addons/sale_override/sale.py:377
2392+#: code:addons/sale_override/sale.py:378
2393+#: code:addons/sale_override/sale.py:1483
2394+#: code:addons/sale_override/sale.py:2035
2395+#: code:addons/sale_override/sale.py:2244
2396+#: code:addons/sale_override/sale.py:2506
2397+#: code:addons/sale_override/sale.py:2578
2398+#: view:sale.order.sourcing.progress:0
2399+#: selection:sale.followup.multi.wizard,state:0
2400+#: selection:sync.monitor,state:0
2401+#: selection:tender.line,line_state:0
2402+#: selection:msf.import.export,state:0
2403 #: selection:wizard.import.invoice.line,state:0
2404 #: selection:hr.payroll.validation,state:0
2405 msgid "Done"
2406@@ -83695,6 +83845,7 @@
2407
2408 #. module: msf_doc_import
2409 #: code:addons/msf_doc_import/wizard/wizard_import_batch.py:312
2410+#: code:addons/msf_doc_import/msf_import_export.py:692
2411 #, python-format
2412 msgid "(see error messages below)"
2413 msgstr "(voir les erreurs ci-dessous)"
2414@@ -84421,7 +84572,7 @@
2415 #: code:addons/msf_doc_import/wizard/abstract_wizard_import.py:354
2416 #, python-format
2417 msgid "Import can be run only on draft wizard."
2418-msgstr "L'important ne peut être effectué que sur des assistants en état 'Non démarré'"
2419+msgstr "L'importation ne peut être effectuée que sur des assistants en état 'Non démarré'"
2420
2421 #. module: account_payment
2422 #: field:payment.line,currency:0
2423@@ -91108,6 +91259,7 @@
2424 #: field:local.transport.cost.report,func_currency_id:0
2425 #: field:local.transport.cost.report,transport_currency_id:0
2426 #: field:purchase.order,transport_currency_id:0
2427+#: code:addons/msf_doc_import/msf_import_export_conf.py:86
2428 #: report:allocation.invoices.report:0
2429 #: report:addons/msf_doc_import/report/po_simulation_screen_xls_report.mako:238
2430 #: report:addons/msf_doc_import/report/po_simulation_screen_xls_report.mako:245
2431@@ -92693,51 +92845,6 @@
2432 msgid "Patches marked as 'not-installed' must have an emission date"
2433 msgstr "Patches marked as 'not-installed' must have an emission date"
2434
2435-#. modules: register_accounting, msf_outgoing, product_attributes, import_data, stock_override, consumption_calculation, specific_rules, kit, account_override, procurement, base, msf_doc_import
2436-#: report:allocation.invoices.report:0
2437-#: selection:res.request,ref_doc1:0
2438-#: selection:res.request,ref_doc2:0
2439-#: field:product.history.consumption.product,product_id:0
2440-#: selection:import_category,object:0
2441-#: selection:import_nomenclature,object:0
2442-#: report:kit.report:0
2443-#: report:addons/msf_doc_import/report/in_simulation_screen_xls_report.mako:149
2444-#: report:addons/msf_doc_import/report/in_simulation_screen_xls_report.mako:158
2445-#: report:addons/msf_doc_import/report/po_simulation_screen_xls_report.mako:230
2446-#: report:addons/msf_doc_import/report/po_simulation_screen_xls_report.mako:241
2447-#: report:po.simulation.screen:0
2448-#: field:product.product.import.line.qty,product_id:0
2449-#: field:wizard.import.in.line.simulation.screen,imp_product_id:0
2450-#: field:wizard.import.in.line.simulation.screen,move_product_id:0
2451-#: field:wizard.import.po.simulation.screen.line,imp_product_id:0
2452-#: field:wizard.import.po.simulation.screen.line,in_product_id:0
2453-#: view:create.picking.move.processor:0
2454-#: field:create.picking.move.processor,product_id:0
2455-#: view:internal.move.processor:0
2456-#: field:internal.move.processor,product_id:0
2457-#: view:outgoing.delivery.move.processor:0
2458-#: field:outgoing.delivery.move.processor,product_id:0
2459-#: view:ppl.move.processor:0
2460-#: field:ppl.move.processor,product_id:0
2461-#: view:return.ppl.move.processor:0
2462-#: field:return.ppl.move.processor,product_id:0
2463-#: view:stock.move.in.processor:0
2464-#: field:stock.move.in.processor,product_id:0
2465-#: view:stock.move.processor:0
2466-#: field:stock.move.processor,product_id:0
2467-#: view:validate.move.processor:0
2468-#: field:validate.move.processor,product_id:0
2469-#: field:stock.warehouse.orderpoint.line,product_id:0
2470-#: view:product.where.used:0
2471-#: field:product.where.used,product_id:0
2472-#: field:standard.price.track.changes,product_id:0
2473-#: field:account.direct.invoice.wizard.line,product_id:0
2474-#: field:unconsistent.stock.report.line,product_id:0
2475-#: view:stock.card.wizard:0
2476-#: field:stock.card.wizard,product_id:0
2477-msgid "Product"
2478-msgstr "Product"
2479-
2480 #. module: report_webkit
2481 #: view:ir.header_webkit:0
2482 msgid "Content and styling"
2483@@ -92870,7 +92977,7 @@
2484 msgid "SQL Constraint"
2485 msgstr "Contrainte SQL"
2486
2487-#. modules: hr, base, msf_homere_interface
2488+#. modules: hr, base, msf_homere_interface, msf_doc_import
2489 #: model:ir.actions.act_window,name:base.action_partner_employee_form
2490 #: view:hr.employee:0
2491 #: field:hr.job,employee_ids:0
2492@@ -92880,6 +92987,7 @@
2493 #: model:ir.ui.menu,name:hr.menu_open_view_employee_list_my
2494 #: model:ir.ui.menu,name:hr.menu_view_employee_category_configuration_form
2495 #: view:hr.employee:0
2496+#: code:addons/msf_doc_import/msf_import_export_conf.py:76
2497 msgid "Employees"
2498 msgstr "Employé(e)s"
2499
2500@@ -95260,11 +95368,11 @@
2501 msgid "GRAND TOTAL"
2502 msgstr "GRAND TOTAL"
2503
2504-#. module: msf_field_access_rights
2505+#. module: msf_field_access_right
2506 #: model:ir.model,name:msf_field_access_rights.model_msf_field_access_rights_field_access_rule_line
2507 #: view:msf_field_access_rights.field_access_rule_line:0
2508 msgid "Field Access Rule Line"
2509-msgstr "Field Access Rule Line"
2510+msgstr "Ligne de Règle d'Accès au Champs"
2511
2512 #. module: account_mcdb
2513 #: view:account.mcdb:0
2514@@ -98029,6 +98137,166 @@
2515 msgid "Article must be used only in a properly designed programme, need a more detailed description."
2516 msgstr "L'article doit être uniquement utilisé dans un programme correctement construit, à besoin d'une description plus détaillée."
2517
2518+#. module: msf_doc_import
2519+#: model:ir.actions.report.xml,name:msf_doc_import.wizard_export_generic
2520+msgid "Generic Export"
2521+msgstr "Export Générique"
2522+
2523+#. module: msf_doc_import
2524+#: field:msf.import.export,model_list_selection:0
2525+msgid "Object to Import/Export"
2526+msgstr "Objet à Importer/Exporter"
2527+
2528+#. module: msf_doc_import
2529+#: field:msf.import.export,import_file:0
2530+msgid "File to import .xml"
2531+msgstr "Fichier à importer .xml"
2532+
2533+#. module: msf_doc_import
2534+#: code:addons/msf_doc_import/msf_import_export.py:93
2535+#, python-format
2536+msgid "%s_Import_Template"
2537+msgstr "%s_Modèle_d_import"
2538+
2539+#. module: msf_doc_import
2540+#: code:addons/msf_doc_import/msf_import_export.py:198
2541+#: code:addons/msf_doc_import/msf_import_export.py:322
2542+#, python-format
2543+msgid "field '%s' not found for model '%s'. Please contact the support team."
2544+msgstr "champ '%s' non trouvé pour le modèle '%s'. Veuillez contacter l'équipe support."
2545+
2546+#. module: msf_doc_import
2547+#: code:addons/msf_doc_import/msf_import_export.py:112
2548+#, python-format
2549+msgid "Selection '%s' not found. Please contact the support team."
2550+msgstr "Sélection '%s' non trouvée. Veuillez contacter l'équipe support."
2551+
2552+#. module: msf_doc_import
2553+#: code:addons/msf_doc_import/msf_import_export.py:117
2554+#, python-format
2555+msgid "The header_list for report '%s' is not defined. Please contact the support team."
2556+msgstr "La liste des entêtes pour le rapport '%s' n'est pas définie. Veuillez contacter l'équipe support."
2557+
2558+#. module: msf_doc_import
2559+#: code:addons/msf_doc_import/msf_import_export.py:264
2560+#, python-format
2561+msgid "File structure is incorrect, please correct. You may generate a template with the File export functionality."
2562+msgstr "La structure du fichier est incorrecte, veuillez corriger. Vous pouvez générer un modèle avec la fonctionnalité d'exportation de modèle."
2563+
2564+#. module: msf_doc_import
2565+#: code:addons/msf_doc_import/msf_import_export.py:272
2566+#, python-format
2567+msgid "File structure is correct."
2568+msgstr "La structure du fichier est correcte."
2569+
2570+#. module: msf_doc_import
2571+#: code:addons/msf_doc_import/msf_import_export.py:325
2572+#, python-format
2573+msgid "Column %s: get '%s' expected '%s'."
2574+msgstr "Colonne %s: reçu '%s' attendu '%s'."
2575+
2576+#. module: msf_doc_import
2577+#: code:addons/msf_doc_import/msf_import_export.py:328
2578+#, python-format
2579+msgid "The following columns are missing in the imported file:\n"
2580+"%s"
2581+msgstr "Les colonnes suivantes sont manquantes dans le fichier importé :\n"
2582+"%s"
2583+
2584+#. module: msf_doc_import
2585+#: code:addons/msf_doc_import/msf_import_export_conf.py:37
2586+#, python-format
2587+msgid "Product Categories"
2588+msgstr "Catégories Produit"
2589+
2590+#. module: msf_doc_import
2591+#: model:ir.actions.act_window,name:msf_doc_import.msf_import_export_non_functional_action
2592+#: model:ir.ui.menu,name:msf_doc_import.msf_import_export_non_functional_menu
2593+msgid "Non Functional"
2594+msgstr "Non Functionnel"
2595+
2596+#. module: msf_doc_import
2597+#: code:addons/msf_doc_import/msf_import_export_conf.py:48
2598+#, python-format
2599+msgid "Supplier Catalogues"
2600+msgstr "Catalogues Fournisseur"
2601+
2602+#. module: msf_doc_import
2603+#: view:msf.import.export:0
2604+#: field:msf.import.export,display_file_import:0
2605+msgid "File Import"
2606+msgstr "Import Fichier"
2607+
2608+#. module: msf_doc_import
2609+#: view:msf.import.export:0
2610+#: field:msf.import.export,display_file_export:0
2611+msgid "File Export"
2612+msgstr "Export Fichier"
2613+
2614+#. module: msf_doc_import
2615+#: view:msf.import.export:0
2616+msgid "Export empty template"
2617+msgstr "Exporter un modèle vide"
2618+
2619+#. module: msf_doc_import
2620+#: view:msf.import.export:0
2621+msgid "Export first 3 entries"
2622+msgstr "Exporter les 3 premières entrées"
2623+
2624+#. module: msf_doc_import
2625+#: view:msf.import.export:0
2626+msgid "Export all data"
2627+msgstr "Exporter toutes les données"
2628+
2629+#. module: msf_doc_import
2630+#: code:addons/msf_doc_import/msf_import_export_conf.py:56
2631+#, python-format
2632+msgid "GL Accounts"
2633+msgstr "Comptes"
2634+
2635+#. module: msf_doc_import
2636+#: code:addons/msf_doc_import/msf_import_export_conf.py:61
2637+#, python-format
2638+msgid "GL Journals"
2639+msgstr "Journaux"
2640+
2641+#. module: msf_doc_import
2642+#: view:msf.import.export:0
2643+msgid "Test file"
2644+msgstr "Tester le fichier"
2645+
2646+#. module: msf_doc_import
2647+#: view:msf.import.export:0
2648+#: view:wizard.import.batch:0
2649+msgid "Download template file"
2650+msgstr "Télécharger un fichier modèle"
2651+
2652+#. module: msf_homere_interface
2653+#: code:addons/msf_homere_interface/hr.py:137
2654+#, python-format
2655+msgid "Some employees have the same unique code: %s"
2656+msgstr "Certains employés ont le même code unique : %s"
2657+
2658+#. modules: msf_doc_import
2659+#: code:addons/msf_doc_import/msf_import_export_conf.py:86
2660+msgid "Currency"
2661+msgstr "Devise"
2662+
2663+#. modules: msf_doc_import
2664+#: code:addons/msf_doc_import/msf_import_export_conf.py:99
2665+msgid "User Access"
2666+msgstr "Accès utilisateur"
2667+
2668+#. modules: msf_doc_import
2669+#: code:addons/msf_doc_import/msf_import_export_conf.py:99
2670+msgid "User Groups"
2671+msgstr "Groupes utilisateur"
2672+
2673+#. modules: msf_doc_import
2674+#: code:addons/msf_doc_import/msf_import_export_conf.py:99
2675+msgid "Currencies Rates"
2676+msgstr "Taux des Devises"
2677+
2678 #. module: account
2679 #: code:addons/account/report/common_report_header.py:136
2680 #, python-format
2681
2682=== modified file 'bin/addons/product_nomenclature/product_nomenclature.py'
2683--- bin/addons/product_nomenclature/product_nomenclature.py 2017-05-29 14:06:25 +0000
2684+++ bin/addons/product_nomenclature/product_nomenclature.py 2017-09-12 08:08:04 +0000
2685@@ -821,7 +821,7 @@
2686 4. duplication from GUI: the default code XXX is saved, then modify in the write
2687 '''
2688 # The first 2 cases: dup of default_code/xmlid_code not allow
2689- if context.get('from_import_menu') or context.get('sync_update_execution', False):
2690+ if context.get('sync_update_execution', False):
2691 if not default_code or not vals.get('xmlid_code', False):
2692 raise Exception, "Problem creating product: Missing xmlid_code/default_code in the data"
2693 if not vals.get('xmlid_code'):
2694
2695=== modified file 'bin/osv/orm.py'
2696--- bin/osv/orm.py 2017-08-18 14:26:52 +0000
2697+++ bin/osv/orm.py 2017-09-12 08:08:04 +0000
2698@@ -675,10 +675,18 @@
2699 elif f[i] in self._inherit_fields.keys():
2700 cols = selection_field(self._inherits)
2701 if cols and cols._type == 'selection' and not sync_context:
2702- sel_list = cols.selection
2703- if r and type(sel_list) == type([]):
2704- r = [x[1] for x in sel_list if r==x[0]]
2705- r = r and r[0] or False
2706+ # if requested, translate the fields.selection values
2707+ translated_selection = False
2708+ if context.get('translate_selection_field', False) and r and f:
2709+ fields_get_res = self.fields_get(cr, uid, f, context=context)
2710+ if f[0] in fields_get_res and 'selection' in fields_get_res[f[0]]:
2711+ r = dict(fields_get_res[f[0]]['selection'])[r]
2712+ translated_selection = True
2713+ if not translated_selection:
2714+ sel_list = cols.selection
2715+ if r and type(sel_list) == type([]):
2716+ r = [x[1] for x in sel_list if r==x[0]]
2717+ r = r and r[0] or False
2718 if not r:
2719 if f[i] in self._columns:
2720 r = check_type(self._columns[f[i]]._type)
2721@@ -935,7 +943,14 @@
2722 if field_type not in ('one2many', 'many2one', 'many2many',
2723 'integer', 'boolean', 'float', 'selection',
2724 'reference'):
2725- res = value
2726+ if not context.get('sync_update_execution', False) and\
2727+ field_type == 'char' and isinstance(value, basestring) \
2728+ and len(value.splitlines()) > 1:
2729+ # US-2661 do not allowed newline character in char fields
2730+ res = False
2731+ warning += [_("New line characters in the field '%s' not allowed. Please fix entry :\n'%s'") % (field[len(prefix)], value)]
2732+ else:
2733+ res = value
2734 elif field_type == 'one2many':
2735 if field[len(prefix)] in done:
2736 continue
2737@@ -1033,27 +1048,40 @@
2738
2739 from osv import except_osv
2740 position = 0
2741+ error_list = []
2742 while position<len(datas):
2743 res = {}
2744
2745 (res, position, warning, res_id, xml_id) = \
2746 process_liness(self, datas, [], current_module, self._name, fields_def, position=position)
2747 if len(warning):
2748- cr.rollback()
2749- return (-1, res, 'Line ' + str(position) +' : ' + '!\n'.join(warning), '')
2750+ if not context.get('sync_update_execution', False):
2751+ error_list.append(_('Line %s: %s') % (str(position), '\n'.join(warning)))
2752+ continue
2753+ else:
2754+ cr.rollback()
2755+ return (-1, res, 'Line ' + str(position) +' : ' + '!\n'.join(warning), '')
2756
2757 try:
2758 ir_model_data_obj._update(cr, uid, self._name,
2759 current_module, res, mode=mode, xml_id=xml_id,
2760 noupdate=noupdate, res_id=res_id, context=context)
2761 except except_osv, e:
2762- cr.rollback()
2763- return (-1, res, 'Line ' + str(position) +' : ' + tools.ustr(e.value), '')
2764+ if not context.get('sync_update_execution', False):
2765+ error_list.append(_('Line %s: %s') % (str(position), tools.ustr(e.value)))
2766+ continue
2767+ else:
2768+ cr.rollback()
2769+ return (-1, res, 'Line ' + str(position) +' : ' + tools.ustr(e.value), '')
2770 except Exception, e:
2771 #US-88: If this from an import account analytic, and there is sql error, AND not sync context, then just clear the cache
2772 if 'account.analytic.account' in self._name and not context.get('sync_update_execution', False):
2773 cache.clean_caches_for_db(cr.dbname)
2774- return (-1, res, 'Line ' + str(position) +' : ' + tools.ustr(e) + "\n" + tools.ustr(traceback.format_exc()), '')
2775+ if not context.get('sync_update_execution', False):
2776+ error_list.append(_('Line %s: %s') % (str(position), tools.ustr(e) + "\n" + tools.ustr(traceback.format_exc())))
2777+ continue
2778+ else:
2779+ return (-1, res, 'Line ' + str(position) +' : ' + tools.ustr(e) + "\n" + tools.ustr(traceback.format_exc()), '')
2780
2781 if config.get('import_partial', False) and filename and (not (position%100)):
2782 data = pickle.load(file(config.get('import_partial')))
2783@@ -1062,6 +1090,9 @@
2784 if context.get('defer_parent_store_computation'):
2785 self._parent_store_compute(cr)
2786 cr.commit()
2787+ if not context.get('sync_update_execution', False) and error_list:
2788+ cr.rollback()
2789+ return (-1, {}, '\n'.join(error_list), '')
2790
2791 if context.get('defer_parent_store_computation'):
2792 self._parent_store_compute(cr)

Subscribers

People subscribed via source and target branches