Merge lp:~dorian-kemps/unifield-server/US-1080 into lp:unifield-server

Proposed by jftempo
Status: Merged
Merged at revision: 5329
Proposed branch: lp:~dorian-kemps/unifield-server/US-1080
Merge into: lp:unifield-server
Diff against target: 2467 lines (+1684/-43) (has conflicts)
15 files modified
bin/addons/msf_doc_import/__openerp__.py (+1/-0)
bin/addons/msf_doc_import/wizard/__init__.py (+5/-0)
bin/addons/msf_doc_import/wizard/wizard_import_product_line.py (+313/-0)
bin/addons/msf_doc_import/wizard/wizard_import_product_line_view.xml (+38/-0)
bin/addons/msf_profile/i18n/fr_MF.po (+466/-40)
bin/addons/product/__openerp__.py (+3/-1)
bin/addons/product/product.py (+29/-1)
bin/addons/product/report/__init__.py (+1/-0)
bin/addons/product/report/product_mass_update_export.py (+55/-0)
bin/addons/product/report/product_mass_update_export_view.xml (+14/-0)
bin/addons/product/report/product_mass_update_export_xls.mako (+146/-0)
bin/addons/product/wizard/__init__.py (+1/-0)
bin/addons/product/wizard/product_mass_update.py (+467/-0)
bin/addons/product/wizard/product_mass_update_view.xml (+139/-0)
bin/addons/product_attributes/product_attributes_view.xml (+6/-1)
Text conflict in bin/addons/msf_profile/i18n/fr_MF.po
To merge this branch: bzr merge lp:~dorian-kemps/unifield-server/US-1080
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+360164@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/addons/msf_doc_import/__openerp__.py'
2--- bin/addons/msf_doc_import/__openerp__.py 2018-04-18 13:37:31 +0000
3+++ bin/addons/msf_doc_import/__openerp__.py 2019-04-15 13:13:32 +0000
4@@ -61,6 +61,7 @@
5 'wizard/wizard_import_threshold_value_line.xml',
6 'wizard/wizard_import_stock_warehouse_order_point_line.xml',
7 'wizard/wizard_import_product_list.xml',
8+ 'wizard/wizard_import_product_line_view.xml',
9 'wizard/wizard_import_supplier_catalogue.xml',
10 'wizard/wizard_po_simulation_screen_view.xml',
11 'wizard/wizard_in_simulation_screen_view.xml',
12
13=== modified file 'bin/addons/msf_doc_import/wizard/__init__.py'
14--- bin/addons/msf_doc_import/wizard/__init__.py 2018-07-04 09:34:39 +0000
15+++ bin/addons/msf_doc_import/wizard/__init__.py 2019-04-15 13:13:32 +0000
16@@ -108,6 +108,10 @@
17 (_('Product Code'), 'string'), (_('Product Description'), 'string'), (_('Comment'), 'string')]
18 PRODUCT_LIST_COLUMNS_FOR_IMPORT = [x for (x,y) in PRODUCT_LIST_COLUMNS_HEADER_FOR_IMPORT]
19
20+COLUMNS_HEADER_FOR_PRODUCT_LINE_IMPORT = [
21+ (_('Product Code'), 'string')]
22+COLUMNS_FOR_PRODUCT_LINE_IMPORT = [x for (x, y) in COLUMNS_HEADER_FOR_PRODUCT_LINE_IMPORT]
23+
24 ACCOUNT_INVOICE_COLUMNS_HEADER_FOR_IMPORT = [
25 ('Description', 'string'), ('Account', 'string'), ('Quantity', 'number'), ('Unit Price', 'number'), ('Destination', 'string'), ('Cost Center', 'string'), ('Funding Pool', 'string')]
26 ACCOUNT_INVOICE_COLUMNS_FOR_IMPORT = [x for (x,y) in ACCOUNT_INVOICE_COLUMNS_HEADER_FOR_IMPORT]
27@@ -153,6 +157,7 @@
28 import wizard_import_threshold_value_line
29 import wizard_import_stock_warehouse_order_point_line
30 import wizard_import_product_list
31+import wizard_import_product_line
32 import wizard_import_supplier_catalogue
33 import wizard_po_simulation_screen
34 import wizard_in_simulation_screen
35
36=== added file 'bin/addons/msf_doc_import/wizard/wizard_import_product_line.py'
37--- bin/addons/msf_doc_import/wizard/wizard_import_product_line.py 1970-01-01 00:00:00 +0000
38+++ bin/addons/msf_doc_import/wizard/wizard_import_product_line.py 2019-04-15 13:13:32 +0000
39@@ -0,0 +1,313 @@
40+# -*- coding: utf-8 -*-
41+##############################################################################
42+#
43+# OpenERP, Open Source Management Solution
44+# Copyright (C) 2011 MSF, TeMPO Consulting.
45+#
46+# This program is free software: you can redistribute it and/or modify
47+# it under the terms of the GNU Affero General Public License as
48+# published by the Free Software Foundation, either version 3 of the
49+# License, or (at your option) any later version.
50+#
51+# This program is distributed in the hope that it will be useful,
52+# but WITHOUT ANY WARRANTY; without even the implied warranty of
53+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54+# GNU Affero General Public License for more details.
55+#
56+# You should have received a copy of the GNU Affero General Public License
57+# along with this program. If not, see <http://www.gnu.org/licenses/>.
58+#
59+##############################################################################
60+import threading
61+import pooler
62+from osv import osv, fields
63+from tools.translate import _
64+import base64
65+from spreadsheet_xml.spreadsheet_xml import SpreadsheetXML
66+import time
67+import tools
68+from msf_doc_import import check_line
69+from msf_doc_import.wizard import COLUMNS_FOR_PRODUCT_LINE_IMPORT as columns_for_product_line_import
70+
71+
72+class wizard_import_product_line(osv.osv_memory):
73+ _name = 'wizard.import.product.line'
74+ _description = 'Import Products data from Excel sheet'
75+
76+ def get_bool_values(self, cr, uid, ids, fields, arg, context=None):
77+ res = {}
78+ if isinstance(ids, (int, long)):
79+ ids = [ids]
80+ for obj in self.browse(cr, uid, ids, context=context):
81+ res[obj.id] = False
82+ if obj.message:
83+ res[obj.id] = True
84+ return res
85+
86+ _columns = {
87+ 'file': fields.binary(string='File to import', required=True, readonly=True, states={'draft': [('readonly', False)]}),
88+ 'message': fields.text(string='Message', readonly=True),
89+ 'product_mass_upd_id': fields.many2one('product.mass.update', string='Product Mass Update', required=True),
90+ 'data': fields.binary('Lines with errors'),
91+ 'filename': fields.char('Lines with errors', size=256),
92+ 'filename_template': fields.char('Templates', size=256),
93+ 'import_error_ok': fields.function(get_bool_values, method=True, readonly=True, type="boolean", string="Error at import", store=False),
94+ 'percent_completed': fields.integer('% completed', readonly=True),
95+ 'state': fields.selection([('draft', 'Draft'), ('in_progress', 'In Progress'), ('done', 'Done')],
96+ string="State", required=True, readonly=True),
97+ }
98+
99+ def _import(self, dbname, uid, ids, context=None):
100+ '''
101+ Import file
102+ '''
103+ cr = pooler.get_db(dbname).cursor()
104+
105+ if context is None:
106+ context = {}
107+ wiz_common_import = self.pool.get('wiz.common.import')
108+ context.update({'import_in_progress': True, 'noraise': True})
109+ start_time = time.time()
110+ obj_data = self.pool.get('ir.model.data')
111+ product_obj = self.pool.get('product.product')
112+ p_mass_upd_obj = self.pool.get('product.mass.update')
113+ line_with_error = []
114+
115+ # Get the expected product creator id
116+ instance_level = self.pool.get('res.users').browse(cr, uid, uid).company_id.instance_id.level
117+ prod_creator_id = False
118+ if instance_level == 'section':
119+ prod_creator_id = obj_data.get_object_reference(cr, uid, 'product_attributes', 'int_3')[1]
120+ elif instance_level == 'coordo':
121+ prod_creator_id = obj_data.get_object_reference(cr, uid, 'product_attributes', 'int_4')[1]
122+
123+ for wiz_browse in self.browse(cr, uid, ids, context):
124+ p_mass_upd_id = wiz_browse.product_mass_upd_id.id
125+ try:
126+ product_ids = [prod.id for prod in wiz_browse.product_mass_upd_id.product_ids]
127+
128+ ignore_lines, complete_lines, lines_to_correct = 0, 0, 0
129+ line_ignored_num = []
130+ error_list = []
131+ error_log = ''
132+ message = ''
133+ line_num = 0
134+ header_index = context['header_index']
135+ mandatory_col_count = 1 # ignore Status column
136+
137+ file_obj = SpreadsheetXML(xmlstring=base64.decodestring(wiz_browse.file))
138+ rows = file_obj.getRows()
139+
140+ header_row = rows.next()
141+ header_error = False
142+
143+ if len(header_row) != mandatory_col_count and len(header_row) != len(columns_for_product_line_import):
144+ header_row = False
145+ header_error = True
146+ error_list.append(_("\n\tNumber of columns is not equal to %s") % len(columns_for_product_line_import))
147+
148+ if header_row:
149+ for i, h_name in enumerate(columns_for_product_line_import):
150+ # To be able to import without Status column
151+ if h_name != 'state' or len(header_row) != mandatory_col_count:
152+ tr_header_row = _(tools.ustr(header_row[i]))
153+ tr_h_name = _(h_name)
154+ if len(header_row) > i and tr_header_row != tr_h_name:
155+ header_error = True
156+ if tr_header_row.upper() == tr_h_name.upper():
157+ error_list.append(_("\n\tPlease check spelling on column '%s'.") % tr_header_row)
158+
159+ if header_error:
160+ msg = _("\n\tYou can not import this file because the header of columns doesn't match with the expected headers: %s") % ','.join([_(x) for x in columns_for_product_line_import])
161+ error_list.append(msg)
162+ msg = _("\n\tPlease ensure that all these columns are present and in this exact order.")
163+ error_list.append(msg)
164+
165+ if not error_list:
166+ # iterator on rows
167+ rows = file_obj.getRows()
168+ rows.next() # skip header
169+ # ignore the first row
170+
171+ line_num = 0
172+ total_line_num = file_obj.getNbRows()
173+ percent_completed = 0
174+ for row in rows:
175+ line_num += 1
176+ error_list_line = []
177+
178+ col_count = len(row)
179+ template_col_count = len(header_index.items())
180+ if col_count != template_col_count and col_count != mandatory_col_count:
181+ message += _("""Line %s in the Excel file: You should have exactly %s columns in this order: %s \n""") % (line_num, template_col_count,','.join(columns_for_fo_line_import))
182+ line_with_error.append(wiz_common_import.get_line_values(cr, uid, ids, row, cell_nb=False, error_list=error_list, line_num=line_num, context=context))
183+ ignore_lines += 1
184+ line_ignored_num.append(line_num)
185+ percent_completed = float(line_num)/float(total_line_num-1)*100.0
186+ self.write(cr, uid, ids, {'percent_completed': percent_completed})
187+ continue
188+ try:
189+ if not check_line.check_empty_line(row=row, col_count=col_count, line_num=line_num):
190+ percent_completed = float(line_num)/float(total_line_num-1)*100.0
191+ self.write(cr, uid, ids, {'percent_completed': percent_completed})
192+ line_num -= 1
193+ total_line_num -= 1
194+ continue
195+
196+ # Cell 0: Product
197+ if row[0]:
198+ prod_ids = product_obj.search(cr, uid, [('default_code', '=ilike', row[0].data),
199+ ('active', 'in', ['t', 'f'])], context=context)
200+ if prod_ids and prod_ids[0] not in product_ids:
201+ prod = product_obj.browse(cr, uid, prod_ids[0], fields_to_fetch=['international_status'], context=context)
202+ if prod_creator_id and prod.international_status.id == prod_creator_id:
203+ product_ids.append(prod.id)
204+ else:
205+ if instance_level == 'section':
206+ error_list_line.append(_('Product %s doesn\'t have the expected Product Creator "HQ". ')
207+ % (row[0].data,))
208+ elif instance_level == 'coordo':
209+ error_list_line.append(_('Product %s doesn\'t have the expected Product Creator "Local". ')
210+ % (row[0].data,))
211+ else:
212+ error_list_line.append(_('You must be on Coordo or HQ instance to add products to the list. '))
213+ elif not prod_ids:
214+ error_list_line.append(_('Product code %s doesn\'t exist in the DB. ') % (row[0].data,))
215+ else:
216+ error_list_line.append(_('Product code is mandatory. '))
217+
218+ if error_list_line:
219+ lines_to_correct += 1
220+ line_txt = _('Line %s: ') % (line_num,)
221+ error_list.append(line_txt + ' '.join(error_list_line))
222+
223+ percent_completed = float(line_num)/float(total_line_num-1)*100.0
224+ complete_lines += 1
225+
226+ except IndexError, e:
227+ error_log += _("Line %s in the Excel file was added to the file of the lines with errors, it got elements outside the defined %s columns. Details: %s") % (line_num, template_col_count, e)
228+ line_with_error.append(wiz_common_import.get_line_values(cr, uid, ids, row, cell_nb=False, error_list=error_list, line_num=line_num, context=context))
229+ ignore_lines += 1
230+ line_ignored_num.append(line_num)
231+ percent_completed = float(line_num)/float(total_line_num-1)*100.0
232+ cr.rollback()
233+ continue
234+ except osv.except_osv as osv_error:
235+ osv_value = osv_error.value
236+ osv_name = osv_error.name
237+ message += _("Line %s in the Excel file: %s: %s\n") % (line_num, osv_name, osv_value)
238+ ignore_lines += 1
239+ line_with_error.append(wiz_common_import.get_line_values(cr, uid, ids, row, cell_nb=False, error_list=error_list, line_num=line_num, context=context))
240+ percent_completed = float(line_num)/float(total_line_num-1)*100.0
241+ cr.rollback()
242+ continue
243+ finally:
244+ self.write(cr, uid, ids, {'percent_completed': percent_completed})
245+ cr.commit()
246+
247+ # Update products
248+ p_mass_upd_obj.write(cr, uid, p_mass_upd_id, {'product_ids': [(6, 0, product_ids)]}, context=context)
249+
250+ error_log += '\n'.join(error_list)
251+ if error_log:
252+ error_log = _("Reported errors for ignored lines : \n") + error_log
253+ end_time = time.time()
254+ total_time = tools.ustr(round(end_time-start_time)) + _(' second(s)')
255+ final_message = _('''
256+ Importation completed in %s!
257+# of imported lines : %s on %s lines
258+# of ignored lines: %s
259+# of lines to correct: %s
260+ %s
261+
262+ %s
263+ ''') % (total_time ,complete_lines, line_num, ignore_lines, lines_to_correct, error_log, message)
264+ wizard_vals = {'message': final_message, 'state': 'done'}
265+ if line_with_error:
266+ file_to_export = wiz_common_import.export_file_with_error(cr, uid, ids, line_with_error=line_with_error, header_index=header_index)
267+ wizard_vals.update(file_to_export)
268+ self.write(cr, uid, ids, wizard_vals, context=context)
269+ # we reset the state of the FO to draft (initial state)
270+ except Exception as e:
271+ self.write(cr, uid, ids, {
272+ 'message': _('An unknow error occurred, please contact the support team. Error message: %s') % tools.ustr(e),
273+ 'state': 'done',
274+ }, context=context)
275+ finally:
276+ p_mass_upd_obj.write(cr, uid, p_mass_upd_id, {'state': 'draft', 'import_in_progress': False}, context)
277+ cr.commit()
278+ cr.close(True)
279+
280+ def import_file(self, cr, uid, ids, context=None):
281+ """
282+ Launch a thread for importing lines.
283+ """
284+ wiz_common_import = self.pool.get('wiz.common.import')
285+ p_mass_upd_obj = self.pool.get('product.mass.update')
286+ for wiz_read in self.read(cr, uid, ids, ['product_mass_upd_id', 'file']):
287+ p_mass_upd_id = wiz_read['product_mass_upd_id']
288+ if not wiz_read['file']:
289+ return self.write(cr, uid, ids, {'message': _("Nothing to import")})
290+ try:
291+ fileobj = SpreadsheetXML(xmlstring=base64.decodestring(wiz_read['file']))
292+ # iterator on rows
293+ reader = fileobj.getRows()
294+ reader_iterator = iter(reader)
295+ # get first line
296+ first_row = next(reader_iterator)
297+ header_index = wiz_common_import.get_header_index(cr, uid, ids, first_row, error_list=[], line_num=0, context=context)
298+ context.update({'p_mass_upd_id': p_mass_upd_id, 'header_index': header_index})
299+ res, res1 = wiz_common_import.check_header_values(cr, uid, ids, context, header_index, columns_for_product_line_import, origin='')
300+ if not res:
301+ return self.write(cr, uid, ids, res1, context)
302+ except osv.except_osv as osv_error:
303+ osv_value = osv_error.value
304+ osv_name = osv_error.name
305+ message = "%s: %s\n" % (osv_name, osv_value)
306+ return self.write(cr, uid, ids, {'message': message})
307+ except StopIteration:
308+ return self.write(cr, uid, ids, {'message': _('The file has no row, nothing to import')})
309+ p_mass_upd_obj.write(cr, uid, p_mass_upd_id, {'state': 'done', 'import_in_progress': True}, context)
310+ thread = threading.Thread(target=self._import, args=(cr.dbname, uid, ids, context))
311+ thread.start()
312+ msg_to_return = _("""Import in progress, please leave this window open and press the button 'Update' when you think that the import is done.
313+Otherwise, you can continue to use Unifield.""")
314+ return self.write(cr, uid, ids, {'message': msg_to_return, 'state': 'in_progress'}, context=context)
315+
316+ def dummy(self, cr, uid, ids, context=None):
317+ """
318+ This button is only for updating the view.
319+ """
320+ if isinstance(ids, (int, long)):
321+ ids = [ids]
322+ for wiz_read in self.read(cr, uid, ids, ['fo_id', 'state', 'file']):
323+ if wiz_read['state'] != 'done':
324+ self.write(cr, uid, ids, {'message': _(' Import in progress... \n Please wait that the import is finished before editing.')})
325+ return False
326+
327+ def cancel(self, cr, uid, ids, context=None):
328+ '''
329+ Return to the initial view. I don't use the special cancel because when I open the wizard with target: crush, and I click on cancel (the special),
330+ I come back on the home page. Here, I come back on the object on which I opened the wizard.
331+ '''
332+ if isinstance(ids, (int, long)):
333+ ids=[ids]
334+ for wiz_obj in self.read(cr, uid, ids, ['product_mass_upd_id']):
335+ p_mass_upd_id = wiz_obj['product_mass_upd_id']
336+ return {'type': 'ir.actions.act_window',
337+ 'res_model': 'product.mass.update',
338+ 'view_type': 'form',
339+ 'view_mode': 'form, tree',
340+ 'target': 'crush',
341+ 'res_id': p_mass_upd_id,
342+ 'context': context,
343+ }
344+
345+ def close_import(self, cr, uid, ids, context=None):
346+ '''
347+ Return to the initial view
348+ '''
349+ return self.cancel(cr, uid, ids, context=context)
350+
351+
352+wizard_import_product_line()
353
354=== added file 'bin/addons/msf_doc_import/wizard/wizard_import_product_line_view.xml'
355--- bin/addons/msf_doc_import/wizard/wizard_import_product_line_view.xml 1970-01-01 00:00:00 +0000
356+++ bin/addons/msf_doc_import/wizard/wizard_import_product_line_view.xml 2019-04-15 13:13:32 +0000
357@@ -0,0 +1,38 @@
358+<?xml version="1.0" encoding="utf-8" ?>
359+<openerp>
360+ <data>
361+
362+ <record id="wizard_to_import_product_line" model="ir.ui.view">
363+ <field name="name">wizard.to.import.product.line</field>
364+ <field name="model">wizard.import.product.line</field>
365+ <field name="type">form</field>
366+ <field name="arch" type="xml">
367+ <form string="Import of lines">
368+ <separator colspan="4" string="File to import" />
369+ <field name="file" filename="filename_template" />
370+ <field name="percent_completed" widget="progressbar" attrs="{'invisible':[('state', '=', 'draft')]}"/>
371+ <field name="filename_template" invisible="1" />
372+ <field name="filename" invisible="1" />
373+ <field name="data" filename="filename" readonly="1"
374+ attrs="{'invisible':[('import_error_ok', '!=', False), ('state', '!=', 'done')]}"/>
375+
376+ <separator colspan="12" string="Information" />
377+ <field name="message" colspan="4" nolabel="1" />
378+ <group name="buttons" string="" colspan="24" col="6">
379+ <button name="cancel" string="Cancel" icon="gtk-cancel" type="object"
380+ attrs="{'invisible':[('state', '!=', 'draft')]}"/>
381+ <button name="import_file" string="Import file" icon="gtk-go-forward" type="object"
382+ attrs="{'invisible':[('state', '!=', 'draft')]}"/>
383+ <button name="dummy" string="Update" icon="gtk-execute" type="object"
384+ attrs="{'invisible':[('state', '!=', 'in_progress')]}"/>
385+ <button name="close_import" string="Close window" icon="gtk-cancel" type="object"
386+ attrs="{'invisible':[('state', '!=', 'done')]}"/>
387+ </group>
388+ <newline/>
389+ <field name="state" colspan="1"/>
390+ </form>
391+ </field>
392+ </record>
393+
394+ </data>
395+</openerp>
396\ No newline at end of file
397
398=== modified file 'bin/addons/msf_profile/i18n/fr_MF.po'
399--- bin/addons/msf_profile/i18n/fr_MF.po 2019-04-08 09:30:07 +0000
400+++ bin/addons/msf_profile/i18n/fr_MF.po 2019-04-15 13:13:32 +0000
401@@ -1200,6 +1200,7 @@
402 #: code:addons/msf_doc_import/wizard/wizard_import_fo_line.py:368
403 #: code:addons/msf_doc_import/wizard/wizard_import_ir_line.py:324
404 #: code:addons/msf_doc_import/wizard/wizard_import_tender_line.py:275
405+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:280
406 #, python-format
407 msgid "Import in progress, please leave this window open and press the button 'Update' when you think that the import is done.\n"
408 "Otherwise, you can continue to use Unifield."
409@@ -1701,10 +1702,11 @@
410 msgid "Backup Size"
411 msgstr "Taille Sauvegarde"
412
413-#. module: product_attributes
414+#. module: product_attributes, product
415 #: selection:product.product,state_ud:0
416+#: selection:product.mass.update,product_state:0
417 msgid "Stopped"
418-msgstr "Arrêter"
419+msgstr "Arrêté"
420
421 #. module: register_accounting
422 #: report:addons/register_accounting/report/liquidity_position_xls.mako:268
423@@ -3826,6 +3828,7 @@
424 #: code:addons/msf_doc_import/wizard/wizard_import_stock_warehouse_order_point_line.py:237
425 #: code:addons/msf_doc_import/wizard/wizard_import_supplier_catalogue.py:382
426 #: code:addons/msf_doc_import/wizard/wizard_import_threshold_value_line.py:200
427+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:190
428 #, python-format
429 msgid "Line %s in the Excel file was added to the file of the lines with errors, it got elements outside the defined %s columns. Details: %s"
430 msgstr "La ligne %s du fichier Excel a été ajoutée au fichier des lignes en erreur, elle a des éléments en dehors des colonnes définies %s. Détails: %s"
431@@ -8636,7 +8639,7 @@
432 msgid "Either there are no moves linked to the picking or Accounting Journals are misconfigured!"
433 msgstr "Soit les Journaux Comptables sont mal configurés, soit il n'y a pas de mouvement connexe à ce prélèvement !"
434
435-#. modules: tender_flow, financing_contract, msf_tools, account_voucher, account_override, purchase_allocation_report, register_accounting, mission_stock, msf_accrual, finance, sync_client, return_claim, account_mcdb, res_currency_tables, supplier_catalogue, procurement_request, stock_forecast, analytic, stock_override, msf_doc_import, analytic_distribution, msf_order_date, account_payment, msf_homere_interface, consumption_calculation, msf_instance, purchase_override, specific_rules, kit, out_step, base, msf_supply_doc_export, msf_budget, account_corrections, account, msf_outgoing, documents_done, sale, sales_followup, procurement, sourcing, purchase, msf_audittrail, stock
436+#. modules: tender_flow, financing_contract, msf_tools, account_voucher, account_override, purchase_allocation_report, register_accounting, mission_stock, msf_accrual, finance, sync_client, return_claim, account_mcdb, res_currency_tables, supplier_catalogue, procurement_request, stock_forecast, analytic, stock_override, msf_doc_import, analytic_distribution, msf_order_date, account_payment, msf_homere_interface, consumption_calculation, msf_instance, purchase_override, specific_rules, kit, out_step, base, msf_supply_doc_export, msf_budget, account_corrections, account, msf_outgoing, documents_done, sale, sales_followup, procurement, sourcing, purchase, msf_audittrail, stock, product
437 #: selection:msf.instance.cloud,state:0
438 #: field:ppl.processor,draft_step1:0
439 #: field:ppl.processor,draft_step2:0
440@@ -8804,7 +8807,12 @@
441 #: field:internal.picking.processor,draft:0
442 #: field:outgoing.delivery.processor,draft:0
443 #: selection:internal.request.import,state:0
444+<<<<<<< TREE
445 #: selection:wizard.import.ppl.to.create.ship,state:0
446+=======
447+#: selection:wizard.import.product.line,state:0
448+#: selection:product.mass.update,state:0
449+>>>>>>> MERGE-SOURCE
450 #, python-format
451 msgid "Draft"
452 msgstr "Brouillon"
453@@ -12401,6 +12409,7 @@
454 #. modules: stock_forecast, product
455 #: selection:product.template,procure_method:0
456 #: selection:stock.forecast,procurement_method:0
457+#: selection:product.mass.update,procure_method:0
458 msgid "Make to Stock"
459 msgstr "Production sur Stock"
460
461@@ -15765,8 +15774,9 @@
462 msgid "total m³"
463 msgstr "total m³"
464
465-#. module: product_expiry
466+#. module: product_expiry, product
467 #: field:product.product,use_time:0
468+#: field:product.mass.update,use_time:0
469 msgid "Product Use Time"
470 msgstr "Produit - Durée d'utilisation "
471
472@@ -16856,7 +16866,7 @@
473 msgid "%s update%s"
474 msgstr "%s update%s"
475
476-#. modules: msf_budget, sales_followup, account, product_attributes, register_accounting, unifield_setup, object_query, order_types, mission_stock, msf_accrual, procurement_report, msf_partner, res_currency_tables, salr, sourcing, tender_flow, msf_doc_import, finance
477+#. modules: msf_budget, sales_followup, account, product_attributes, register_accounting, unifield_setup, object_query, order_types, mission_stock, msf_accrual, procurement_report, msf_partner, res_currency_tables, salr, sourcing, tender_flow, msf_doc_import, finance, product
478 #: view:account.state.open:0
479 #: selection:mission.stock.wizard,split_stock:0
480 #: selection:mission.stock.wizard,with_valuation:0
481@@ -16903,6 +16913,13 @@
482 #: selection:po.automation.config,name:0
483 #: view:tender.cancel.wizard:0
484 #: view:tender.line.cancel.wizard:0
485+#: selection:product.mass.update,active_product:0
486+#: selection:product.mass.update,dangerous_goods:0
487+#: selection:product.mass.update,heat_sensitive_item:0
488+#: selection:product.mass.update,short_shelf_life:0
489+#: selection:product.mass.update,single_use:0
490+#: selection:product.mass.update,sterilized:0
491+#: report:addons/product/report/product_mass_update_export_xls.mako:136
492 #, python-format
493 msgid "No"
494 msgstr "Non"
495@@ -17320,8 +17337,9 @@
496 msgid "Error! The nomenclature complete name must be unique."
497 msgstr "Error! The nomenclature complete name must be unique."
498
499-#. module: service_purchasing
500+#. module: service_purchasing, product
501 #: code:addons/service_purchasing/service_purchasing.py:70
502+#: code:addons/product/wizard/product_mass_update.py:328
503 #, python-format
504 msgid "You must select on order procurement method for %s products."
505 msgstr "Vous devez sélectionner 'Sur commande' comme méthode d'acquisition pour les produits %s."
506@@ -17708,6 +17726,7 @@
507
508 #. module: product
509 #: help:product.template,state:0
510+#: help:product.mass.update,product_state:0
511 msgid "Tells the user if he can use the product or not."
512 msgstr "Indique à l'utilisateur s'il peut ou ne peut pas utiliser le produit."
513
514@@ -18038,8 +18057,9 @@
515 msgid "The record exists in database?"
516 msgstr "The record exists in database?"
517
518-#. module: product_attributes
519+#. module: product_attributes, product
520 #: field:product.product,single_use:0
521+#: field:product.mass.update,single_use:0
522 msgid "Single Use"
523 msgstr "Utilisation unique"
524
525@@ -22386,8 +22406,9 @@
526 msgid "Wizard Name"
527 msgstr "Nom de l'Assistant"
528
529-#. module: procurement
530+#. module: procurement, product
531 #: help:procurement.order,procure_method:0
532+#: help:product.mass.update,procure_method:0
533 msgid "If you encode manually a Procurement, you probably want to use a make to order method."
534 msgstr "Si vous saisissez manuellement un Approvisionnement, vous voulez probablement utiliser une méthode Production sur Commande"
535
536@@ -22855,7 +22876,11 @@
537 #: view:wizard.import.threshold.value.line:0
538 #: view:automated.import.job:0
539 #: view:procurement.request.import:0
540+<<<<<<< TREE
541 #: view:wizard.import.ppl.to.create.ship:0
542+=======
543+#: view:wizard.import.product.line:0
544+>>>>>>> MERGE-SOURCE
545 msgid "Import file"
546 msgstr "Importer le fichier"
547
548@@ -25231,7 +25256,7 @@
549 msgid "Europe/Bucharest"
550 msgstr "Europe/Bucharest"
551
552-#. modules: msf_budget, account, account_payment, product_attributes, register_accounting, unifield_setup, object_query, order_types, mission_stock, msf_accrual, procurement_report, stock, msf_partner, salr, sourcing, tender_flow, msf_doc_import, finance
553+#. modules: msf_budget, account, account_payment, product_attributes, register_accounting, unifield_setup, object_query, order_types, mission_stock, msf_accrual, procurement_report, stock, msf_partner, salr, sourcing, tender_flow, msf_doc_import, finance, product
554 #: view:account.state.open:0
555 #: view:account.payment.make.payment:0
556 #: selection:mission.stock.wizard,split_stock:0
557@@ -25271,6 +25296,13 @@
558 #: selection:po.automation.config,name:0
559 #: view:tender.cancel.wizard:0
560 #: view:tender.line.cancel.wizard:0
561+#: selection:product.mass.update,active_product:0
562+#: selection:product.mass.update,dangerous_goods:0
563+#: selection:product.mass.update,heat_sensitive_item:0
564+#: selection:product.mass.update,short_shelf_life:0
565+#: selection:product.mass.update,single_use:0
566+#: selection:product.mass.update,sterilized:0
567+#: report:addons/product/report/product_mass_update_export_xls.mako:136
568 #, python-format
569 msgid "Yes"
570 msgstr "Oui"
571@@ -25313,8 +25345,9 @@
572 msgid "Adds commitment, requested and effective dates on Sales Orders."
573 msgstr "Ajoute les dates d'engagement, désirées et effectives sur les commandes terrains."
574
575-#. module: product_list
576+#. module: product_list, product
577 #: view:product.to.list:0
578+#: view:product.mass.update:0
579 msgid "Import products"
580 msgstr "Importer les produits"
581
582@@ -27660,7 +27693,7 @@
583 msgid "Asia/Omsk"
584 msgstr "Asia/Omsk"
585
586-#. module: msf_doc_import
587+#. module: msf_doc_import, product
588 #: field:stock.partial.picking,percent_completed:0
589 #: field:wizard.import.auto.supply.line,percent_completed:0
590 #: field:wizard.import.fo.line,percent_completed:0
591@@ -27675,6 +27708,9 @@
592 #: field:wizard.import.supplier.catalogue,percent_completed:0
593 #: field:wizard.import.tender.line,percent_completed:0
594 #: field:wizard.import.threshold.value.line,percent_completed:0
595+#: field:wizard.import.product.line,percent_completed:0
596+#: field:product.mass.update,percent_completed:0
597+#: field:product.mass.update.progressbar,percent_completed:0
598 msgid "% completed"
599 msgstr "% terminé"
600
601@@ -31708,6 +31744,8 @@
602 #: field:wizard.import.threshold.value.line,data:0
603 #: field:wizard.import.threshold.value.line,filename:0
604 #: field:internal.request.import,error_filename:0
605+#: field:wizard.import.product.line,data:0
606+#: field:wizard.import.product.line,filename:0
607 msgid "Lines with errors"
608 msgstr "Lignes avec des erreurs"
609
610@@ -32129,8 +32167,9 @@
611 msgid "RFQ - closed"
612 msgstr "Demande de Devis- fermé"
613
614-#. module: product_expiry
615+#. module: product_expiry, product
616 #: help:product.product,use_time:0
617+#: help:product.mass.update,use_time:0
618 msgid "The number of months before a production lot starts deteriorating without becoming dangerous."
619 msgstr "Nombre de mois avant qu'un lot de production ne commence à se détériorer, sans être dangereux"
620
621@@ -33391,10 +33430,11 @@
622 msgid "Asia/Dushanbe"
623 msgstr "Asia/Dushanbe"
624
625-#. module: product_attributes
626+#. module: product_attributes, product
627 #: selection:product.product,state_ud:0
628+#: selection:product.mass.update,product_state:0
629 msgid "Phase Out"
630-msgstr "Phase Out"
631+msgstr "Élimination"
632
633 #. module: sync_so
634 #: field:purchase.order,push_fo:0
635@@ -34481,8 +34521,9 @@
636 msgid "From comparison to closed."
637 msgstr "De comparaison à fermé."
638
639-#. module: product_expiry
640+#. module: product_expiry, product
641 #: help:product.product,alert_time:0
642+#: help:product.mass.update,alert_time:0
643 msgid "The number of months after which an alert should be notified about the production lot."
644 msgstr "Nombre de mois après lequel une alerte devrait être affichée en ce qui concerne le lot de production."
645
646@@ -34823,7 +34864,7 @@
647 msgid "IR/FO Order"
648 msgstr "IR/FO Order"
649
650-#. modules: purchase, account, analytic_distribution_supply, msf_homere_interface, res_currency_tables, register_accounting, account_hq_entries, account_corrections, product_attributes, base, account_subscription, analytic_distribution, purchase_override
651+#. modules: purchase, account, analytic_distribution_supply, msf_homere_interface, res_currency_tables, register_accounting, account_hq_entries, account_corrections, product_attributes, base, account_subscription, analytic_distribution, purchase_override, product
652 #: selection:account.entries.report,move_line_state:0
653 #: selection:account.move.line,state:0
654 #: selection:wizard.journal.items.corrections.lines,analytic_distribution_state:0
655@@ -34846,6 +34887,7 @@
656 #: selection:wizard.advance.line,analytic_distribution_state:0
657 #: selection:res.currency.table,state:0
658 #: selection:purchase.order.merged.line,analytic_distribution_state:0
659+#: selection:product.mass.update,product_state:0
660 msgid "Valid"
661 msgstr "Valide"
662
663@@ -36109,7 +36151,11 @@
664 msgid "cancel_voucher - (account.voucher)"
665 msgstr "cancel_voucher - (account.voucher)"
666
667+<<<<<<< TREE
668 #. modules: sales_followup, msf_homere_interface, msf_field_access_rights, consumption_calculation, sale, update_client, product_attributes, purchase_followup, sf_doc_import, register_accounting, finance, msf_supply_doc_export, product_nomenclature, account_mcdb
669+=======
670+#. modules: sales_followup, msf_homere_interface, msf_field_access_rights, consumption_calculation, sale, update_client, product_attributes, purchase_followup, msf_doc_import, register_accounting, finance, msf_supply_doc_export, product
671+>>>>>>> MERGE-SOURCE
672 #: field:cash.request.liquidity,status:0
673 #: field:cash.request.liquidity.bank,status:0
674 #: field:cash.request.liquidity.cash,status:0
675@@ -36140,9 +36186,14 @@
676 #: report:addons/sales_followup/report/ir_track_changes_report_xls.mako:224
677 #: report:addons/register_accounting/report/fully_report_xls.mako:590
678 #: report:addons/msf_supply_doc_export/report/report_internal_request_xls.mako:65
679+<<<<<<< TREE
680 #: field:product.nomenclature,status:0
681 #: report:addons/account_mcdb/report/combined_journals_report.mako:273
682 #: report:combined.journals.report.pdf:0
683+=======
684+#: field:product.mass.update,product_state:0
685+#: field:product.mass.update,state:0
686+>>>>>>> MERGE-SOURCE
687 #, python-format
688 msgid "Status"
689 msgstr "Statut"
690@@ -42634,7 +42685,7 @@
691 msgid "Contract code/name:"
692 msgstr "Contrat - Code/Nom:"
693
694-#. modules: sales_followup, register_accounting, import_data, sync_client, base, purchase_followup, msf_doc_import, stock
695+#. modules: sales_followup, register_accounting, import_data, sync_client, base, purchase_followup, msf_doc_import, stock, product
696 #: view:base.module.update:0
697 #: view:base.update.translations:0
698 #: selection:import_data,import_mode:0
699@@ -42661,7 +42712,12 @@
700 #: view:product.product:0
701 #: model:ir.ui.menu,name:sync_client.update_menu
702 #: view:sync.client.update_entity:0
703+<<<<<<< TREE
704 #: view:stock.expired.damaged.report:0
705+=======
706+#: view:wizard.import.product.line:0
707+#: view:product.mass.update:0
708+>>>>>>> MERGE-SOURCE
709 msgid "Update"
710 msgstr "Mettre à jour"
711
712@@ -44041,7 +44097,11 @@
713 msgid "Contains Dangerous goods"
714 msgstr "Contient des Produits Dangereux"
715
716+<<<<<<< TREE
717 #. modules: sales_followup, register_accounting, stock_override, order_nomenclature, consumption_calculation, product_asset, specific_rules, account_override, supplier_catalogue, product_list, tender_flow, msf_supply_doc_export, msf_doc_import, stock_forecast, purchase_allocation_report, procurement_request, kit, purchase_compare_rfq, stock
718+=======
719+#. modules: sales_followup, register_accounting, stock_override, order_nomenclature, consumption_calculation, product_asset, specific_rules, account_override, supplier_catalogue, product_list, tender_flow, msf_supply_doc_export, msf_doc_import, stock_forecast, purchase_allocation_report, procurement_request, kit, purchase_compare_rfq, product
720+>>>>>>> MERGE-SOURCE
721 #: field:account.invoice.line,product_code:0
722 #: code:addons/consumption_calculation/consumption_calculation.py:482
723 #: report:addons/consumption_calculation/report/report_real_consumption_xls.mako:69
724@@ -44106,9 +44166,13 @@
725 #: report:addons/msf_supply_doc_export/report/internal_request_export_xls.mako:130
726 #: code:addons/sale/wizard/internal_request_import.py:43
727 #: report:addons/procurement_request/report/internal_request_import_overview_export_xls.mako:214
728+<<<<<<< TREE
729 #: report:addons/specific_rules/report/report_stock_inventory_xls.mako:223
730 #: report:addons/stock/report/stock_reception_report_xls.mako:237
731 #: report:addons/stock/report/stock_expired_damaged_report_xls.mako:218
732+=======
733+#: report:addons/product/report/product_mass_update_export_xls.mako:113
734+>>>>>>> MERGE-SOURCE
735 #, python-format
736 msgid "Product Code"
737 msgstr "Code Produit"
738@@ -44253,8 +44317,9 @@
739 msgid "Portrait"
740 msgstr "Portrait"
741
742-#. module: consumption_calculation
743+#. module: consumption_calculation, product
744 #: help:product.product,procure_delay:0
745+#: help:product.mass.update,procure_delay:0
746 msgid "It's the default time to procure this product. This lead time will be used on the Order cycle procurement computation"
747 msgstr "C'est le temps nécessaire par défaut pour se procurer ce produit. Ce délai de livraison sera utilisé lors du calcul du cycle de commandes d'approvisionnement."
748
749@@ -44718,11 +44783,12 @@
750
751 #. module: msf_doc_import
752 #: code:addons/msf_doc_import/wizard/wizard_import_fo_line.py:131
753+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:121
754 #, python-format
755 msgid "\n"
756 " Please check spelling on column '%s'."
757 msgstr "\n"
758-" Please check spelling on column '%s'."
759+" Veuillez vérifier l'orthographe sur la colonne '%s'."
760
761 #. module: sync_client
762 #: view:sync.monitor:0
763@@ -45688,6 +45754,7 @@
764 #: field:stock.location,stock_virtual_specific:0
765 #: field:stock.location,stock_virtual:0
766 #: selection:product.price.type,field:0
767+#: report:addons/product/report/product_mass_update_export_xls.mako:116
768 msgid "Virtual Stock"
769 msgstr "Stock Virtuel"
770
771@@ -46516,6 +46583,7 @@
772
773 #. module: msf_doc_import
774 #: code:addons/msf_doc_import/wizard/wizard_import_fo_line.py:134
775+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:124
776 #, python-format
777 msgid "\n"
778 " You can not import this file because the header of columns doesn't match with the expected headers: %s"
779@@ -47552,8 +47620,9 @@
780 msgid "RfQ Line Ref"
781 msgstr "Réf. Ligne Demande de Devis"
782
783-#. module: product_expiry
784+#. module: product_expiry, product
785 #: field:product.product,alert_time:0
786+#: field:product.mass.update,alert_time:0
787 msgid "Product Alert Time"
788 msgstr "Produit - Période d'Alerte"
789
790@@ -48746,7 +48815,7 @@
791 #: code:addons/msf_doc_import/wizard/wiz_common_import.py:108
792 #, python-format
793 msgid "The column \"%s\" is not taken into account. Please correct it. The list of columns accepted is: %s"
794-msgstr "La colone \"%s\" n'est pas prise en compte. Merci de corriger. La liste des colonnes acceptée est : %s"
795+msgstr "La colonne \"%s\" n'est pas prise en compte. Merci de corriger. La liste des colonnes acceptée est : %s"
796
797 #. module: msf_outgoing
798 #: report:picking.ticket:0
799@@ -51280,7 +51349,7 @@
800 msgid "Indian/Mayotte"
801 msgstr "Indien/Mayotte"
802
803-#. modules: purchase, register_accounting, supplier_catalogue, sale, account_override, msf_doc_import
804+#. modules: purchase, register_accounting, supplier_catalogue, sale, account_override, msf_doc_import, product
805 #: view:account.invoice:0
806 #: view:composition.kit:0
807 #: view:initial.stock.inventory:0
808@@ -51298,6 +51367,7 @@
809 #: view:account.invoice:0
810 #: view:sale.order:0
811 #: view:supplier.catalogue:0
812+#: view:product.mass.update:0
813 msgid " Import Lines "
814 msgstr "Importer les Lignes"
815
816@@ -52436,10 +52506,11 @@
817 msgid "Line Number"
818 msgstr "Numéro de Ligne"
819
820-#. module: product_nomenclature
821+#. module: product_nomenclature, product
822 #: help:product.category,active:0
823 #: help:product.nomenclature,active:0
824 #: help:product.uom.categ,active:0
825+#: help:product.mass.update,active_product:0
826 msgid "If the active field is set to False, it allows to hide the nomenclature without removing it."
827 msgstr "Si ce champ actif est configuré sur Faux, cela permet de cacher la nomenclature sans la supprimer."
828
829@@ -54626,7 +54697,12 @@
830 msgid "Nb treated lines"
831 msgstr "Nb lignes traitées"
832
833-#. module: product_attributes
834+#. module: product_attributes, product
835+#: selection:product.mass.update,dangerous_goods:0
836+#: selection:product.mass.update,heat_sensitive_item:0
837+#: selection:product.mass.update,short_shelf_life:0
838+#: selection:product.mass.update,single_use:0
839+#: selection:product.mass.update,sterilized:0
840 #: selection:product.product,dangerous_goods:0
841 #: selection:product.product,short_shelf_life:0
842 #: selection:product.product,single_use:0
843@@ -57925,8 +58001,9 @@
844 msgid "FX rates by currency table"
845 msgstr "FX rates by currency table"
846
847-#. module: product_attributes
848+#. module: product_attributes, product
849 #: field:product.product,sterilized:0
850+#: field:product.mass.update,sterilized:0
851 msgid "Sterile"
852 msgstr "Stérile"
853
854@@ -63884,8 +63961,9 @@
855 msgid "Sales Management"
856 msgstr "Gestion des Commandes de Terrain"
857
858-#. module: product_expiry
859+#. module: product_expiry, product
860 #: field:product.product,life_time:0
861+#: field:product.mass.update,life_time:0
862 msgid "Product Life Time"
863 msgstr "Durée de vie du produit"
864
865@@ -64402,10 +64480,11 @@
866 msgid "Accrual Account"
867 msgstr "Compte de Régularisation"
868
869-#. module: account
870+#. module: account, product
871 #: view:account.chart.template:0
872 #: field:product.category,property_account_income_categ:0
873 #: field:product.template,property_account_income:0
874+#: field:product.mass.update,property_account_income:0
875 msgid "Income Account"
876 msgstr "Compte de Produits "
877
878@@ -65943,8 +66022,9 @@
879 msgid "Proprietary instance:"
880 msgstr "Instance propriétaire :"
881
882-#. module: account
883+#. module: account, product
884 #: help:product.template,property_account_expense:0
885+#: help:product.mass.update,property_account_expense:0
886 msgid "This account will be used for invoices instead of the default one to value expenses for the current product"
887 msgstr "Ce compte sera utilisé pour les factures au lieu de celui utilisé par défaut lors de la valorisation des dépenses du produit actuel"
888
889@@ -66152,6 +66232,7 @@
890
891 #. module: msf_doc_import
892 #: code:addons/msf_doc_import/wizard/wizard_import_fo_line.py:322
893+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:236
894 #, python-format
895 msgid "An unknow error occurred, please contact the support team. Error message: %s"
896 msgstr "Une erreur inconnue est survenue, veuillez contacter votre équipe support. Message d'erreur : %s"
897@@ -68438,6 +68519,7 @@
898 #: view:stock.production.lot:0
899 #: field:stock.location,stock_real:0
900 #: field:stock.production.lot,stock_available:0
901+#: report:addons/product/report/product_mass_update_export_xls.mako:115
902 msgid "Real Stock"
903 msgstr "Stock Réel"
904
905@@ -69686,6 +69768,7 @@
906 #: field:threshold.value,line_ids:0
907 #: field:threshold.value,product_ids:0
908 #: view:restrictive.country.setup:0
909+#: view:product.mass.update:0
910 #, python-format
911 msgid "Products"
912 msgstr "Produits"
913@@ -70267,6 +70350,7 @@
914
915 #. module: product
916 #: help:product.template,supply_method:0
917+#: help:product.mass.update,supply_method:0
918 msgid "Produce will generate production order or tasks, according to the product type. Purchase will trigger purchase orders when requested."
919 msgstr "Produire' génère une commande de production ou tâches, en fonction du type de produit. 'Acheter' va générer des bons de commandes à la demande."
920
921@@ -71718,11 +71802,12 @@
922 msgid "Expected Ship Date"
923 msgstr "Date Prévue d'Expédition"
924
925-#. modules: account, msf_accrual
926+#. modules: account, msf_accrual, product
927 #: view:account.chart.template:0
928 #: field:product.category,property_account_expense_categ:0
929 #: field:product.template,property_account_expense:0
930 #: field:msf.accrual.line,expense_account_id:0
931+#: field:product.mass.update,property_account_expense:0
932 msgid "Expense Account"
933 msgstr "Compte de Charge"
934
935@@ -72845,6 +72930,7 @@
936 #: field:product.heat_sensitive,active:0
937 #: field:sync.client.message_rule,active:0
938 #: selection:sync.version.instance.monitor,instance_state:0
939+#: field:product.mass.update,active_product:0
940 #, python-format
941 msgid "Active"
942 msgstr "Actif"
943@@ -73532,7 +73618,7 @@
944 msgid "Expected Pack Date"
945 msgstr "Date Prévue de Colisage"
946
947-#. modules: tender_flow, analytic_distribution_supply, product_nomenclature, financing_contract, msf_tools, account_hq_entries, export_import_lang, account_override, procurement_cycle, account_journal, register_accounting, mission_stock, return_claim, sync_client, account_mcdb, res_currency_tables, supplier_catalogue, stock_schedule, procurement_request, spreadsheet_xml, unifield_setup, purchase_compare_rfq, stock_batch_recall, purchase_followup, stock_override, msf_doc_import, analytic_distribution, msf_order_date, msf_cross_docking, reason_types_moves, purchase_allocation_report, finance, msf_homere_interface, msf_instance, account_reconciliation, service_purchasing, consumption_calculation, purchase_override, specific_rules, kit, base, account_subscription, res_currency_functional, msf_budget, account_corrections, account, msf_outgoing, stock_move_tracking, msf_partner, product_attributes, order_nomenclature, documents_done, sale, msf_config_locations, sales_followup, sourcing, msf_custom_settings, product_list, object_query, stock, msf_profile
948+#. modules: tender_flow, analytic_distribution_supply, product_nomenclature, financing_contract, msf_tools, account_hq_entries, export_import_lang, account_override, procurement_cycle, account_journal, register_accounting, mission_stock, return_claim, sync_client, account_mcdb, res_currency_tables, supplier_catalogue, stock_schedule, procurement_request, spreadsheet_xml, unifield_setup, purchase_compare_rfq, stock_batch_recall, purchase_followup, stock_override, msf_doc_import, analytic_distribution, msf_order_date, msf_cross_docking, reason_types_moves, purchase_allocation_report, finance, msf_homere_interface, msf_instance, account_reconciliation, service_purchasing, consumption_calculation, purchase_override, specific_rules, kit, base, account_subscription, res_currency_functional, msf_budget, account_corrections, account, msf_outgoing, stock_move_tracking, msf_partner, product_attributes, order_nomenclature, documents_done, sale, msf_config_locations, sales_followup, sourcing, msf_custom_settings, product_list, object_query, stock, msf_profile, product
949 #: code:addons/account/account.py:294
950 #: code:addons/account/account.py:988
951 #: code:addons/account/account.py:992
952@@ -74643,6 +74729,12 @@
953 #: code:addons/sale/wizard/internal_request_import.py:166
954 #: code:addons/msf_outgoing/wizard/create_picking_processor.py:55
955 #: selection:internal.request.import,state:0
956+#: code:addons/product/wizard/product_mass_update.py:182
957+#: code:addons/product/wizard/product_mass_update.py:198
958+#: code:addons/product/wizard/product_mass_update.py:204
959+#: code:addons/product/wizard/product_mass_update.py:210
960+#: code:addons/product/wizard/product_mass_update.py:216
961+#: selection:product.mass.update,state:0
962 #, python-format, python-format
963 msgid "Error"
964 msgstr "Erreur"
965@@ -74822,8 +74914,9 @@
966 #: view:purchase.order.confirm.wizard:0
967 #: view:purchase.order.cancel.wizard:0
968 #: view:tender.line.cancel.wizard:0
969+#: view:wizard.import.product.line:0
970 msgid "Close window"
971-msgstr "Ferme la fenêtre"
972+msgstr "Fermer la fenêtre"
973
974 #. module: msf_outgoing
975 #: code:addons/msf_outgoing/msf_outgoing.py:968
976@@ -75544,6 +75637,7 @@
977 #: field:multiple.sourcing.wizard,type:0
978 #: field:stock.forecast,procurement_method:0
979 #: report:stock.forecast.report:0
980+#: field:product.mass.update,procure_method:0
981 msgid "Procurement Method"
982 msgstr "Approvisionnement- Méthode"
983
984@@ -76058,8 +76152,9 @@
985 msgid "To validate"
986 msgstr "A valider"
987
988-#. module: account
989+#. module: account, product
990 #: help:product.template,property_account_income:0
991+#: help:product.mass.update,property_account_income:0
992 msgid "This account will be used for invoices instead of the default one to value sales for the current product"
993 msgstr "Ce compte sera utilisé pour les factures au lieu de celui utilisé par défaut lors de la valorisation des ventes du produit actuel"
994
995@@ -77240,6 +77335,7 @@
996 #: code:addons/msf_doc_import/wizard/wizard_import_tender_line.py:196
997 #: code:addons/msf_doc_import/wizard/wizard_import_threshold_value_line.py:210
998 #: code:addons/msf_doc_import/wizard/wizard_import_threshold_value_line.py:219
999+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:200
1000 #, python-format
1001 msgid "Line %s in the Excel file: %s: %s\n"
1002 ""
1003@@ -80311,6 +80407,7 @@
1004 #. modules: stock_forecast, product
1005 #: selection:product.template,supply_method:0
1006 #: selection:stock.forecast,supply_method:0
1007+#: selection:product.mass.update,supply_method:0
1008 msgid "Buy"
1009 msgstr "Acheter"
1010
1011@@ -83036,7 +83133,11 @@
1012 #: report:addons/msf_supply_doc_export/report/internal_request_export_xls.mako:89
1013 #: report:addons/procurement_request/report/internal_request_import_overview_export_xls.mako:173
1014 #: field:internal.request.import,state:0
1015+<<<<<<< TREE
1016 #: field:wizard.import.ppl.to.create.ship,state:0
1017+=======
1018+#: field:wizard.import.product.line,state:0
1019+>>>>>>> MERGE-SOURCE
1020 #, python-format
1021 msgid "State"
1022 msgstr "État"
1023@@ -83970,6 +84071,7 @@
1024 #: field:reserved.products.wizard,product_id:0
1025 #: field:internal.request.import.line,imp_product_id:0
1026 #: field:internal.request.import.line,in_product_id:0
1027+#: field:product.mass.update.errors,product_id:0
1028 #, python-format
1029 msgid "Product"
1030 msgstr "Produit"
1031@@ -84073,7 +84175,7 @@
1032 msgid "Select a supplier"
1033 msgstr "Sélectionner un fournisseur"
1034
1035-#. modules: delivery_mechanism, msf_budget, account, msf_outgoing, account_payment, msf_homere_interface, sync_client, register_accounting, specific_rules, sale, sales_followup, base, stock, tender_flow, msf_tools, return_claim, msf_doc_import, analytic_distribution, finance
1036+#. modules: delivery_mechanism, msf_budget, account, msf_outgoing, account_payment, msf_homere_interface, sync_client, register_accounting, specific_rules, sale, sales_followup, base, stock, tender_flow, msf_tools, return_claim, msf_doc_import, analytic_distribution, finance, product
1037 #: selection:account.invoice.report,state:0
1038 #: selection:account.journal.period,state:0
1039 #: selection:account.subscription,state:0
1040@@ -84139,7 +84241,12 @@
1041 #: code:addons/sale/sale_order.py:3207
1042 #: code:addons/sale/sale_order.py:3208
1043 #: selection:internal.request.import,state:0
1044+<<<<<<< TREE
1045 #: selection:wizard.import.ppl.to.create.ship,state:0
1046+=======
1047+#: selection:wizard.import.product.line,state:0
1048+#: selection:product.mass.update,state:0
1049+>>>>>>> MERGE-SOURCE
1050 #, python-format
1051 msgid "Done"
1052 msgstr "Terminé"
1053@@ -84899,7 +85006,7 @@
1054 msgid "Sourced-n line"
1055 msgstr "Ligne sourcée-n"
1056
1057-#. modules: analytic_distribution, sales_followup, register_accounting, reason_types_moves, msf_homere_interface, stock_override, consumption_calculation, sale, specific_rules, order_types, msf_tools, mission_stock, msf_doc_import
1058+#. modules: analytic_distribution, sales_followup, register_accounting, reason_types_moves, msf_homere_interface, stock_override, consumption_calculation, sale, specific_rules, order_types, msf_tools, mission_stock, msf_doc_import, product
1059 #: field:import.commitment.wizard,in_progress:0
1060 #: view:product.history.consumption:0
1061 #: selection:product.history.consumption,fake_status:0
1062@@ -84938,7 +85045,12 @@
1063 #: selection:sale.followup.multi.wizard,state:0
1064 #: selection:export.report.stock.inventory,state:0
1065 #: selection:export.report.stock.move,state:0
1066+<<<<<<< TREE
1067 #: selection:wizard.import.ppl.to.create.ship,state:0
1068+=======
1069+#: selection:wizard.import.product.line,state:0
1070+#: selection:product.mass.update,state:0
1071+>>>>>>> MERGE-SOURCE
1072 #, python-format
1073 msgid "In Progress"
1074 msgstr "En cours"
1075@@ -85935,9 +86047,10 @@
1076 msgid "Asia/Harbin"
1077 msgstr "Asia/Harbin"
1078
1079-#. module: stock_forecast
1080+#. module: stock_forecast, product
1081 #: field:stock.forecast,dangerous_goods:0
1082 #: report:stock.forecast.report:0
1083+#: field:product.mass.update,dangerous_goods:0
1084 msgid "Dangerous Goods"
1085 msgstr "Marchandises Dangereuses"
1086
1087@@ -86411,6 +86524,7 @@
1088 #. modules: consumption_calculation, product
1089 #: selection:product.price.type,field:0
1090 #: field:product.product,procure_delay:0
1091+#: field:product.mass.update,procure_delay:0
1092 msgid "Procurement Lead Time"
1093 msgstr "Délai d'approvisionnement"
1094
1095@@ -88148,10 +88262,11 @@
1096 msgid "Invisible expiry date"
1097 msgstr "Invisible expiry date"
1098
1099-#. modules: stock_forecast, product_attributes
1100+#. modules: stock_forecast, product_attributes, product
1101 #: field:product.product,short_shelf_life:0
1102 #: field:stock.forecast,short_shelf_life:0
1103 #: report:stock.forecast.report:0
1104+#: field:product.mass.update,short_shelf_life:0
1105 msgid "Short Shelf Life"
1106 msgstr "Durée de Conservation Limitée "
1107
1108@@ -88534,6 +88649,8 @@
1109 #: field:physical.inventory,file_to_import2:0
1110 #: field:supplier.catalogue,file_to_import:0
1111 #: field:internal.request.import,file_to_import:0
1112+#: view:wizard.import.product.line:0
1113+#: field:wizard.import.product.line,file:0
1114 msgid "File to import"
1115 msgstr "Fichier à importer"
1116
1117@@ -91514,6 +91631,7 @@
1118 #: model:process.node,name:procurement.process_node_serviceonorder0
1119 #: selection:product.template,procure_method:0
1120 #: selection:stock.forecast,procurement_method:0
1121+#: selection:product.mass.update,procure_method:0
1122 msgid "Make to Order"
1123 msgstr "Production sur Commande"
1124
1125@@ -92913,6 +93031,7 @@
1126 #. modules: stock_forecast, product
1127 #: selection:product.template,supply_method:0
1128 #: selection:stock.forecast,supply_method:0
1129+#: selection:product.mass.update,supply_method:0
1130 msgid "Produce"
1131 msgstr "Produire"
1132
1133@@ -95866,9 +95985,10 @@
1134 msgid "This ISO code is the name of po files to use for translations"
1135 msgstr "Ce code ISO est le nom des fichiers po utilisés pour les traductions"
1136
1137-#. module: product_attributes, purchase
1138+#. module: product_attributes, purchase, product
1139 #: field:product.product,heat_sensitive_item:0
1140 #: field:purchase.order.line,heat_sensitive_item:0
1141+#: field:product.mass.update,heat_sensitive_item:0
1142 msgid "Temperature sensitive item"
1143 msgstr "Article sensible à la température"
1144
1145@@ -97010,9 +97130,10 @@
1146 msgid "Last reviewed on (hidden)"
1147 msgstr "Revu la dernière fois le (caché)"
1148
1149-#. module: stock_forecast
1150+#. module: stock_forecast, product
1151 #: field:stock.forecast,supply_method:0
1152 #: report:stock.forecast.report:0
1153+#: field:product.mass.update,supply_method:0
1154 msgid "Supply Method"
1155 msgstr "Méthode d'Approvisionnement"
1156
1157@@ -98079,7 +98200,11 @@
1158 #: view:integrity.finance.wizard:0
1159 #: view:stock.move.cancel.wizard:0
1160 #: view:stock.picking.cancel.wizard:0
1161+<<<<<<< TREE
1162 #: view:wizard.pick.import:0
1163+=======
1164+#: view:wizard.import.product.line:0
1165+>>>>>>> MERGE-SOURCE
1166 #, python-format
1167 msgid "Cancel"
1168 msgstr "Annuler"
1169@@ -99636,8 +99761,9 @@
1170 msgid "Available Shipped"
1171 msgstr "Disponible expédié"
1172
1173-#. module: product_attributes
1174+#. module: product_attributes, product
1175 #: selection:product.product,state_ud:0
1176+#: selection:product.mass.update,product_state:0
1177 msgid "Archived"
1178 msgstr "Archivé"
1179
1180@@ -101236,8 +101362,9 @@
1181 msgid "Page need to be refreshed - please press \"F5\""
1182 msgstr "La page doit être rafraîchie, veuillez cliquer sur \"F5\""
1183
1184-#. module: product_expiry
1185+#. module: product_expiry, product
1186 #: help:product.product,life_time:0
1187+#: help:product.mass.update,life_time:0
1188 msgid "The number of months before a production lot may become dangerous and should not be consumed."
1189 msgstr "Nombre de mois avant qu'un lot de production ne devienne dangereux et qu'il ne puisse plus être consommé."
1190
1191@@ -103871,6 +103998,7 @@
1192 #, python-format
1193 msgid "Source Location %s is inactive"
1194 msgstr "La Zone Source %s est inactive"
1195+<<<<<<< TREE
1196
1197 #. module: sale
1198 #: report:addons/sale/report/sale_donation_stock_moves_report_xls.mako:140
1199@@ -105388,3 +105516,301 @@
1200 #, python-format
1201 msgid "Product %s, BN: %s not enough stock to process quantity %s %s (stock level: %s)"
1202 msgstr "Produit %s, Lot: %s, pas assez de stock pour traiter la qantité %s %s (quantité en stock: %s)"
1203+=======
1204+
1205+#. module: product
1206+#: model:ir.ui.menu,name:product.parent_product_mass_update
1207+msgid "Products Update"
1208+msgstr "MàJ de Produits"
1209+
1210+#. module: product
1211+#: field:product.product,expected_prod_creator:0
1212+msgid "Expected Product Creator for Product Mass Update"
1213+msgstr "Créateur Produit attendu pour la MàJ de Produits en Masse"
1214+
1215+#. module: product
1216+#: model:ir.model,name:product.model_product_mass_update_progressbar
1217+msgid "Product Mass Update Progress Bar"
1218+msgstr "Barre de Progression de la MàJ de Produits en Masse"
1219+
1220+#. module: product
1221+#: code:addons/product/wizard/product_mass_update.py:343
1222+#: model:ir.actions.report.xml,name:product.product_mass_update_export_xls
1223+#: report:addons/product/report/product_mass_update_export_xls.mako:92
1224+#, python-format
1225+msgid "Product Mass Update Errors"
1226+msgstr "Erreurs de la MàJ de Produits en Masse"
1227+
1228+#. modules: msf_doc_import, product, product_attributes
1229+#: field:wizard.import.product.line,product_mass_upd_id:0
1230+#: model:ir.actions.act_window,name:product.previous_mass_update_action
1231+#: model:ir.model,name:product.model_product_mass_update
1232+#: view:product.mass.update:0
1233+#: field:product.mass.update.progressbar,p_mass_upd_id:0
1234+#: model:ir.ui.menu,name:product_attributes.menu_import_request
1235+msgid "Product Mass Update"
1236+msgstr "MàJ de Produits en Masse"
1237+
1238+#. module: product
1239+#: field:product.mass.update,date_done:0
1240+msgid "Date of the update"
1241+msgstr "Date de la mise à jour"
1242+
1243+#. module: product
1244+#: field:product.mass.update,seller_id:0
1245+msgid "Default Partner"
1246+msgstr "Partenaire par Défaut"
1247+
1248+#. module: product
1249+#: view:product.mass.update:0
1250+msgid " New Data "
1251+msgstr " Nouvelles Données "
1252+
1253+#. module: product
1254+#: view:product.mass.update:0
1255+msgid "Delete Update"
1256+msgstr "Supprimer la Mise à Jour"
1257+
1258+#. module: product
1259+#: view:product.mass.update:0
1260+msgid "Apply Update"
1261+msgstr "Appliquer la Mise à Jour"
1262+
1263+#. module: msf_doc_import
1264+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:219
1265+#, python-format
1266+msgid "\n"
1267+" Importation completed in %s!\n"
1268+"# of imported lines : %s on %s lines\n"
1269+"# of ignored lines: %s\n"
1270+"# of lines to correct: %s\n"
1271+" %s\n"
1272+"\n"
1273+" %s\n"
1274+" "
1275+msgstr "\n"
1276+" Import terminé en %s!\n"
1277+"# de lignes importées : %s sur %s lignes\n"
1278+"# de lignes ignorées: %s\n"
1279+"# de lignes à corriger: %s\n"
1280+" %s\n"
1281+"\n"
1282+" %s\n"
1283+" "
1284+
1285+#. module: msf_doc_import
1286+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:177
1287+#, python-format
1288+msgid "Product code %s doesn't exist in the DB. "
1289+msgstr "Le Code Produit %s n'existe pas dans la BDD. "
1290+
1291+#. module: msf_doc_import
1292+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:110
1293+#, python-format
1294+msgid "\n"
1295+" Number of columns is not equal to %s"
1296+msgstr "\n"
1297+" Le nombre de colonnes n'est pas égal à %s"
1298+
1299+#. module: msf_doc_import
1300+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:169
1301+#, python-format
1302+msgid "Product %s doesn't have the expected Product Creator \"HQ\". "
1303+msgstr "Le Produit %s n'a pas le Créateur Produit attendu \"HQ\". "
1304+
1305+#. module: msf_doc_import
1306+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:254
1307+#, python-format
1308+msgid "Nothing to import"
1309+msgstr "Rien à importer"
1310+
1311+#. module: msf_doc_import
1312+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:183
1313+#, python-format
1314+msgid "Line %s: "
1315+msgstr "Ligne %s: "
1316+
1317+#. module: msf_doc_import
1318+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:145
1319+#, python-format
1320+msgid "Line %s in the Excel file: You should have exactly %s columns in this order: %s \n"
1321+""
1322+msgstr "Ligne %s du fichier Excel: Vous devriez avoir exactement %s colonnes dans cet ordre: %s \n"
1323+""
1324+
1325+#. module: msf_doc_import
1326+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:292
1327+#, python-format
1328+msgid " Import in progress... \n"
1329+" Please wait that the import is finished before editing."
1330+msgstr " Import en cours... \n"
1331+" Veuillez attendre que l'import soit terminer avant de faire des modifications."
1332+
1333+#. module: msf_doc_import
1334+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:218
1335+#, python-format
1336+msgid " second(s)"
1337+msgstr " seconde(s)"
1338+
1339+#. module: msf_doc_import
1340+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:172
1341+#, python-format
1342+msgid "Product %s doesn't have the expected Product Creator \"Local\". "
1343+msgstr "Le Produit %s n'a pas le Créateur Produit attendu \"Local\". "
1344+
1345+#. module: msf_doc_import
1346+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:179
1347+#, python-format
1348+msgid "Product code is mandatory. "
1349+msgstr "Le Code Produit est obligatoire. "
1350+
1351+#. module: msf_doc_import
1352+#: code:addons/msf_doc_import/wizard/wizard_import_fo_line.py:136
1353+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:126
1354+#, python-format
1355+msgid "\n"
1356+" Please ensure that all these columns are present and in this exact order."
1357+msgstr "\n"
1358+" Veuillez vous assurer que toutes les colonnes sont présentes et dans cet ordre."
1359+
1360+#. module: msf_doc_import
1361+#: model:ir.model,name:msf_doc_import.model_wizard_import_product_line
1362+msgid "Import Products data from Excel sheet"
1363+msgstr "Import des données de Produits depuis la feuille Excel"
1364+
1365+#. module: msf_doc_import
1366+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:216
1367+#, python-format
1368+msgid "Reported errors for ignored lines : \n"
1369+""
1370+msgstr "Erreurs signalées pour les lignes ignorées : \n"
1371+""
1372+
1373+#. module: msf_doc_import
1374+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:175
1375+#, python-format
1376+msgid "You must be on Coordo or HQ instance to add products to the list. "
1377+msgstr "Vous devez etre sur une instance Coordo ou HQ pour ajouter des produits à la liste. "
1378+
1379+#. module: msf_doc_import
1380+#: code:addons/msf_doc_import/wizard/wizard_import_product_line.py:273
1381+#, python-format
1382+msgid "The file has no row, nothing to import"
1383+msgstr "Le fichier n'a pas de ligne, il n'y a rien à importer"
1384+
1385+#. module: product
1386+#: selection:product.mass.update,product_state:0
1387+msgid "Status 1"
1388+msgstr "Statut 1"
1389+
1390+#. module: product
1391+#: selection:product.mass.update,product_state:0
1392+msgid "Status 2"
1393+msgstr "Statut 2"
1394+
1395+#. module: product
1396+#: code:addons/product/wizard/product_mass_update.py:210
1397+#, python-format
1398+msgid "Use Time must be an integer."
1399+msgstr "La Durée d'utilisation doit être un entier."
1400+
1401+#. module: product
1402+#: code:addons/product/wizard/product_mass_update.py:198
1403+#, python-format
1404+msgid "Alert Time must be an integer."
1405+msgstr "La Période d'Alerte doit être un entier."
1406+
1407+#. module: product
1408+#: code:addons/product/wizard/product_mass_update.py:204
1409+#, python-format
1410+msgid "Life Time must be an integer."
1411+msgstr "La Durée de Vie d'un produit doit être un entier."
1412+
1413+#. module: product
1414+#: code:addons/product/wizard/product_mass_update.py:216
1415+#, python-format
1416+msgid "Procurement Lead Time must be a float."
1417+msgstr "Le Délai d'approvisionnement doit être nombre à virgule."
1418+
1419+#. module: product
1420+#: code:addons/product/wizard/product_mass_update.py:237
1421+#, python-format
1422+msgid "Update in progress, please leave this window open and press the button 'Update' when you think that the update is done. Otherwise, you can continue to use Unifield."
1423+msgstr "Mise à jour en cours, veuillez laisser cette fenêtre ouverte et appuyer sur le bouton 'Mettre à jour' lorsque vous pensez que la mise à jour est finie. Sinon, vous pouvez continuer à utiliser Unifield."
1424+
1425+#. module: product
1426+#: view:product.mass.update:0
1427+msgid "Non-Deactivable Products"
1428+msgstr "Produits Non-Désactivables"
1429+
1430+#. module: product
1431+#: view:product.mass.update:0
1432+msgid "Export Product List"
1433+msgstr "Exporter la Liste des Produits"
1434+
1435+#. module: product
1436+#: report:addons/product/report/product_mass_update_export_xls.mako:104
1437+msgid "PRODUCT MASS UPDATE ERRORS"
1438+msgstr "ERREURS DE LA MÀJ DE PRODUITS EN MASSE"
1439+
1440+#. module: product
1441+#: view:product.mass.update:0
1442+msgid "Reset Update"
1443+msgstr "Réinitialiser la Mise à Jour"
1444+
1445+#. module: product
1446+#: code:addons/product/wizard/product_mass_update.py:182
1447+#, python-format
1448+msgid "You can not apply an update on no products."
1449+msgstr "Vous ne pouvez pas appliquer de mise à jour à aucun produits."
1450+
1451+#. module: product
1452+#: code:addons/product/wizard/product_mass_update.py:287
1453+msgid "Some products could not be deactivated. No product will be changed until all of them can be deactivated. Please check the corresponding tab."
1454+msgstr "Certains produits n'ont pas pu être désactivés. Aucun produit ne sera modifié tant qu'ils ne pourront pas tous être désactivés. Veuillez vérifier l'onglet approprié."
1455+
1456+#. module: product
1457+#: field:product.mass.update,name:0
1458+msgid "Update Reference"
1459+msgstr "Référence de la MàJ"
1460+
1461+#. module: product
1462+#: field:product.mass.update.errors,stock_exist:0
1463+#: report:addons/product/report/product_mass_update_export_xls.mako:119
1464+msgid "Stock Exist"
1465+msgstr "Stock Présent"
1466+
1467+#. module: product
1468+#: field:product.mass.update.errors,open_documents:0
1469+#: report:addons/product/report/product_mass_update_export_xls.mako:119
1470+msgid "Open Documents"
1471+msgstr "Documents Ouverts"
1472+
1473+#. module: product
1474+#: code:addons/product/wizard/product_mass_update.py:323
1475+#, python-format
1476+msgid "An error has occured during the update:\n"
1477+"%s"
1478+msgstr "Une erreur est survenue lors de la mise à jour:\n"
1479+"%s"
1480+
1481+#. module: product
1482+#: field:product.mass.update,user_id:0
1483+msgid "User who Updated"
1484+msgstr "Utilisateur qui a Mis à Jour"
1485+
1486+#. module: product
1487+#: field:product.mass.update,empty_exp_account:0
1488+msgid "Set Expense Account as empty"
1489+msgstr "Mettre le Compte de Charge à vide"
1490+
1491+#. module: product
1492+#: field:product.mass.update,empty_inc_account:0
1493+msgid "Set Income Account as empty"
1494+msgstr "Mettre le Compte de Produits à vide"
1495+
1496+#. module: product
1497+#: field:product.mass.update,empty_status:0
1498+msgid "Set Status as empty"
1499+msgstr "Mettre le Statut à vide"
1500+>>>>>>> MERGE-SOURCE
1501
1502=== modified file 'bin/addons/product/__openerp__.py'
1503--- bin/addons/product/__openerp__.py 2017-09-28 14:05:02 +0000
1504+++ bin/addons/product/__openerp__.py 2019-04-15 13:13:32 +0000
1505@@ -54,7 +54,9 @@
1506 'product_report.xml',
1507 'product_view.xml',
1508 'pricelist_view.xml',
1509- 'process/product_process.xml'
1510+ 'process/product_process.xml',
1511+ 'wizard/product_mass_update_view.xml',
1512+ 'report/product_mass_update_export_view.xml',
1513 ],
1514 'test':[],
1515 'installable': True,
1516
1517=== modified file 'bin/addons/product/product.py'
1518--- bin/addons/product/product.py 2019-02-08 16:56:18 +0000
1519+++ bin/addons/product/product.py 2019-04-15 13:13:32 +0000
1520@@ -588,6 +588,34 @@
1521 (data['name'] or '') + (data['variants'] and (' - '+data['variants']) or '')
1522 return res
1523
1524+ def _get_expected_prod_creator(self, cr, uid, ids, field_names, arg, context=None):
1525+ if context is None:
1526+ context = {}
1527+
1528+ res = {}
1529+ for id in ids:
1530+ res[id] = False
1531+
1532+ return res
1533+
1534+ def _expected_prod_creator_search(self, cr, uid, obj, name, args, context=None):
1535+ '''
1536+ Returns all documents according to the product creator
1537+ '''
1538+ if context is None:
1539+ context = {}
1540+
1541+ obj_data = self.pool.get('ir.model.data')
1542+ instance_level = self.pool.get('res.users').browse(cr, uid, uid).company_id.instance_id.level
1543+ prod_creator_id = False
1544+ for arg in args:
1545+ if arg[0] == 'expected_prod_creator':
1546+ if instance_level == 'section':
1547+ prod_creator_id = obj_data.get_object_reference(cr, uid, 'product_attributes', 'int_3')[1]
1548+ elif instance_level == 'coordo':
1549+ prod_creator_id = obj_data.get_object_reference(cr, uid, 'product_attributes', 'int_4')[1]
1550+
1551+ return [('international_status', '=', prod_creator_id)]
1552
1553 _defaults = {
1554 'active': lambda *a: 1,
1555@@ -619,9 +647,9 @@
1556 'price_margin': fields.float('Variant Price Margin', digits_compute=dp.get_precision('Sale Price')),
1557 'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
1558 'name_template': fields.related('product_tmpl_id', 'name', string="Name", type='char', size=128, store=True, write_relate=False),
1559+ 'expected_prod_creator': fields.function(_get_expected_prod_creator, method=True, type='many2one', relation='product.international.status', fnct_search=_expected_prod_creator_search, readonly=True, string='Expected Product Creator for Product Mass Update'),
1560 }
1561
1562-
1563 def unlink(self, cr, uid, ids, context=None):
1564 unlink_ids = []
1565 unlink_product_tmpl_ids = []
1566
1567=== modified file 'bin/addons/product/report/__init__.py'
1568--- bin/addons/product/report/__init__.py 2011-01-14 00:11:01 +0000
1569+++ bin/addons/product/report/__init__.py 2019-04-15 13:13:32 +0000
1570@@ -19,6 +19,7 @@
1571 #
1572 ##############################################################################
1573 import product_pricelist
1574+import product_mass_update_export
1575
1576 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1577
1578
1579=== added file 'bin/addons/product/report/product_mass_update_export.py'
1580--- bin/addons/product/report/product_mass_update_export.py 1970-01-01 00:00:00 +0000
1581+++ bin/addons/product/report/product_mass_update_export.py 2019-04-15 13:13:32 +0000
1582@@ -0,0 +1,55 @@
1583+# -*- coding: utf-8 -*-
1584+##############################################################################
1585+#
1586+# OpenERP, Open Source Management Solution
1587+# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
1588+#
1589+# This program is free software: you can redistribute it and/or modify
1590+# it under the terms of the GNU Affero General Public License as
1591+# published by the Free Software Foundation, either version 3 of the
1592+# License, or (at your option) any later version.
1593+#
1594+# This program is distributed in the hope that it will be useful,
1595+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1596+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1597+# GNU Affero General Public License for more details.
1598+#
1599+# You should have received a copy of the GNU Affero General Public License
1600+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1601+#
1602+##############################################################################
1603+
1604+from report import report_sxw
1605+from spreadsheet_xml.spreadsheet_xml_write import SpreadsheetReport
1606+from tools.translate import _
1607+
1608+
1609+class product_mass_update_export_parser(report_sxw.rml_parse):
1610+
1611+ def __init__(self, cr, uid, name, context):
1612+ super(product_mass_update_export_parser, self).__init__(cr, uid, name, context=context)
1613+ self.counter = 0
1614+ self.localcontext.update({
1615+ 'getErrors': self.get_errors,
1616+ })
1617+
1618+ def get_errors(self):
1619+ upd_errors = []
1620+
1621+ if not self.ids:
1622+ return upd_errors
1623+
1624+ for upd_error in self.pool.get('product.mass.update').browse(self.cr, self.uid, self.ids[0], fields_to_fetch=['not_deactivated_product_ids'], context=self.localcontext).not_deactivated_product_ids:
1625+ upd_errors.append({
1626+ 'default_code': upd_error.product_id.default_code,
1627+ 'name': upd_error.product_id.name,
1628+ 'stock_exist': upd_error.stock_exist,
1629+ 'qty_available': upd_error.product_id.qty_available,
1630+ 'virtual_available': upd_error.product_id.virtual_available,
1631+ 'open_documents': upd_error.open_documents,
1632+ })
1633+
1634+ return upd_errors
1635+
1636+
1637+SpreadsheetReport('report.product_mass_update_export_xls', 'product.mass.update', 'addons/product/report/product_mass_update_export_xls.mako', parser=product_mass_update_export_parser)
1638
1639=== added file 'bin/addons/product/report/product_mass_update_export_view.xml'
1640--- bin/addons/product/report/product_mass_update_export_view.xml 1970-01-01 00:00:00 +0000
1641+++ bin/addons/product/report/product_mass_update_export_view.xml 2019-04-15 13:13:32 +0000
1642@@ -0,0 +1,14 @@
1643+<?xml version="1.0" encoding="utf-8" ?>
1644+<openerp>
1645+ <data>
1646+ <report
1647+ id="product_mass_update_export_xls"
1648+ string="Product Mass Update Errors"
1649+ model="product.mass.update"
1650+ name="product_mass_update_export_xls"
1651+ file="product/report/product_mass_update_export_xls.mako"
1652+ report_type="webkit"
1653+ menu="False"
1654+ />
1655+ </data>
1656+</openerp>
1657\ No newline at end of file
1658
1659=== added file 'bin/addons/product/report/product_mass_update_export_xls.mako'
1660--- bin/addons/product/report/product_mass_update_export_xls.mako 1970-01-01 00:00:00 +0000
1661+++ bin/addons/product/report/product_mass_update_export_xls.mako 2019-04-15 13:13:32 +0000
1662@@ -0,0 +1,146 @@
1663+<?xml version="1.0"?>
1664+<?mso-application progid="Excel.Sheet"?>
1665+<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
1666+ xmlns:o="urn:schemas-microsoft-com:office:office"
1667+ xmlns:x="urn:schemas-microsoft-com:office:excel"
1668+ xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
1669+ xmlns:html="http://www.w3.org/TR/REC-html40">
1670+ <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
1671+ <Author>Unifield</Author>
1672+ <LastAuthor>MSFUser</LastAuthor>
1673+ <Created>2014-04-16T22:36:07Z</Created>
1674+ <Company>Medecins Sans Frontieres</Company>
1675+ <Version>11.9999</Version>
1676+ </DocumentProperties>
1677+ <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
1678+ <WindowHeight>11640</WindowHeight>
1679+ <WindowWidth>15480</WindowWidth>
1680+ <WindowTopX>120</WindowTopX>
1681+ <WindowTopY>75</WindowTopY>
1682+ <ProtectStructure>False</ProtectStructure>
1683+ <ProtectWindows>False</ProtectWindows>
1684+ </ExcelWorkbook>
1685+ <Styles>
1686+ <Style ss:ID="ssCell">
1687+ <Alignment ss:Vertical="Top" ss:WrapText="1"/>
1688+ <Font ss:Bold="1" />
1689+ </Style>
1690+ <Style ss:ID="ssCellBlue">
1691+ <Alignment ss:Vertical="Top" ss:WrapText="1"/>
1692+ <Font ss:Color="#0000FF" />
1693+ </Style>
1694+
1695+ <!-- File header -->
1696+ <Style ss:ID="big_header">
1697+ <Font x:Family="Swiss" ss:Size="14" ss:Bold="1"/>
1698+ </Style>
1699+ <Style ss:ID="file_header">
1700+ <Font ss:Size="10" />
1701+ <Interior ss:Color="#C0C0C0" ss:Pattern="Solid"/>
1702+ </Style>
1703+
1704+ <!-- Line header -->
1705+ <Style ss:ID="line_header">
1706+ <Borders>
1707+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>
1708+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>
1709+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>
1710+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>
1711+ </Borders>
1712+ <Font x:Family="Swiss" ss:Size="10" ss:Bold="1"/>
1713+ <Interior/>
1714+ </Style>
1715+
1716+ <!-- Lines -->
1717+ <Style ss:ID="line_left">
1718+ <Alignment ss:Horizontal="Left" ss:Vertical="Bottom"/>
1719+ <Borders>
1720+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>
1721+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>
1722+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>
1723+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>
1724+ </Borders>
1725+ <Font ss:Size="10" />
1726+ <NumberFormat ss:Format="#0"/>
1727+ </Style>
1728+ <Style ss:ID="line_right">
1729+ <Alignment ss:Horizontal="Right" ss:Vertical="Bottom"/>
1730+ <Borders>
1731+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>
1732+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>
1733+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>
1734+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>
1735+ </Borders>
1736+ <Font ss:Size="10" />
1737+ <NumberFormat ss:Format="#0"/>
1738+ </Style>
1739+ <Style ss:ID="line_center">
1740+ <Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
1741+ <Borders>
1742+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>
1743+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>
1744+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>
1745+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>
1746+ </Borders>
1747+ <Font ss:Size="10" />
1748+ <NumberFormat ss:Format="#0"/>
1749+ </Style>
1750+</Styles>
1751+
1752+
1753+% for r in objects:
1754+<ss:Worksheet ss:Name="${_('Product Mass Update Errors')|x}">
1755+ <Table x:FullColumns="1" x:FullRows="1">
1756+ ## Product code
1757+ <Column ss:AutoFitWidth="1" ss:Width="150.00" />
1758+ ## Product code
1759+ <Column ss:AutoFitWidth="1" ss:Width="300.00" />
1760+ ## Stock Exist
1761+ <Column ss:AutoFitWidth="1" ss:Width="70.00" />
1762+ ## Real Stock
1763+ <Column ss:AutoFitWidth="1" ss:Width="80.00" />
1764+ ## Virtual Stock
1765+ <Column ss:AutoFitWidth="1" ss:Width="80.00" />
1766+ ## Open Documents
1767+ <Column ss:AutoFitWidth="1" ss:Width="500.00" />
1768+
1769+ <Row ss:Height="18">
1770+ <Cell ss:StyleID="big_header" ss:MergeAcross="1"><Data ss:Type="String">${_('PRODUCT MASS UPDATE ERRORS')|x}</Data><NamedCell ss:Name="Print_Area"/></Cell>
1771+ </Row>
1772+
1773+ <Row></Row>
1774+
1775+ ## WORKSHEET HEADER
1776+
1777+ <%
1778+ headers_list = [
1779+ _('Product Code'),
1780+ _('Description'),
1781+ _('Stock Exist'),
1782+ _('Real Stock'),
1783+ _('Virtual Stock'),
1784+ _('Open Documents'),
1785+ ]
1786+ %>
1787+
1788+ <Row>
1789+ % for h in headers_list:
1790+ <Cell ss:StyleID="line_header"><Data ss:Type="String">${h|x}</Data></Cell>
1791+ % endfor
1792+ </Row>
1793+
1794+ % for upd_errors in getErrors():
1795+ <Row>
1796+ <Cell ss:StyleID="line_left"><Data ss:Type="String">${upd_errors.get('default_code', '')|x}</Data></Cell>
1797+ <Cell ss:StyleID="line_left"><Data ss:Type="String">${upd_errors.get('name', '')|x}</Data></Cell>
1798+ <Cell ss:StyleID="line_left"><Data ss:Type="String">${upd_errors.get('stock_exist', '') and _('Yes') or _('No')|x}</Data></Cell>
1799+ <Cell ss:StyleID="line_right"><Data ss:Type="Number">${upd_errors.get('qty_available', 0)|x}</Data></Cell>
1800+ <Cell ss:StyleID="line_right"><Data ss:Type="Number">${upd_errors.get('virtual_available', 0)|x}</Data></Cell>
1801+ <Cell ss:StyleID="line_left"><Data ss:Type="String">${upd_errors.get('open_documents', '')|x}</Data></Cell>
1802+ </Row>
1803+ % endfor
1804+ </Table>
1805+
1806+</ss:Worksheet>
1807+% endfor
1808+</Workbook>
1809
1810=== modified file 'bin/addons/product/wizard/__init__.py'
1811--- bin/addons/product/wizard/__init__.py 2011-01-14 00:11:01 +0000
1812+++ bin/addons/product/wizard/__init__.py 2019-04-15 13:13:32 +0000
1813@@ -19,6 +19,7 @@
1814 #
1815 ##############################################################################
1816 import product_price
1817+import product_mass_update
1818
1819 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1820
1821
1822=== added file 'bin/addons/product/wizard/product_mass_update.py'
1823--- bin/addons/product/wizard/product_mass_update.py 1970-01-01 00:00:00 +0000
1824+++ bin/addons/product/wizard/product_mass_update.py 2019-04-15 13:13:32 +0000
1825@@ -0,0 +1,467 @@
1826+# -*- coding: utf-8 -*-
1827+##############################################################################
1828+#
1829+# OpenERP, Open Source Management Solution
1830+# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
1831+#
1832+# This program is free software: you can redistribute it and/or modify
1833+# it under the terms of the GNU Affero General Public License as
1834+# published by the Free Software Foundation, either version 3 of the
1835+# License, or (at your option) any later version.
1836+#
1837+# This program is distributed in the hope that it will be useful,
1838+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1839+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1840+# GNU Affero General Public License for more details.
1841+#
1842+# You should have received a copy of the GNU Affero General Public License
1843+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1844+#
1845+##############################################################################
1846+
1847+from osv import osv, fields
1848+from tools.translate import _
1849+import tools
1850+import time
1851+import base64
1852+import threading
1853+import pooler
1854+from msf_doc_import import GENERIC_MESSAGE
1855+from spreadsheet_xml.spreadsheet_xml_write import SpreadsheetCreator
1856+from spreadsheet_xml.spreadsheet_xml import SpreadsheetXML
1857+from msf_doc_import.wizard import COLUMNS_HEADER_FOR_PRODUCT_LINE_IMPORT as columns_header_for_product_line_import
1858+from msf_doc_import.wizard import COLUMNS_FOR_PRODUCT_LINE_IMPORT as columns_for_product_line_import
1859+
1860+
1861+class product_mass_update(osv.osv):
1862+ _name = 'product.mass.update'
1863+ _description = 'Product Mass Update'
1864+
1865+ _order = 'id desc'
1866+
1867+ def _get_percent_completed(self, cr, uid, ids, field_names, arg, context=None):
1868+ if context is None:
1869+ context = {}
1870+
1871+ upd_progress_obj = self.pool.get('product.mass.update.progressbar')
1872+
1873+ res = {}
1874+ for p_mass_upd in self.browse(cr, uid, ids, fields_to_fetch=['state'], context=context):
1875+ if p_mass_upd.state == 'done':
1876+ res[p_mass_upd.id] = 100
1877+ else:
1878+ upd_progress_ids = upd_progress_obj.search(cr, uid, [('p_mass_upd_id', '=', p_mass_upd.id)], context=context)
1879+ if upd_progress_ids:
1880+ res[p_mass_upd.id] = round(upd_progress_obj.browse(cr, uid, upd_progress_ids[0], context=context).percent_completed, 0) or 0
1881+
1882+ return res
1883+
1884+ _columns = {
1885+ 'name': fields.char(size=64, string='Update Reference'),
1886+ 'state': fields.selection(selection=[('draft', 'Draft'), ('in_progress', 'In Progress'), ('error', 'Error'), ('done', 'Done')], string='Status', readonly=True),
1887+ 'date_done': fields.datetime(string='Date of the update'),
1888+ 'user_id': fields.many2one('res.users', string='User who Updated', readonly=True),
1889+ 'import_in_progress': fields.boolean(string='Import in progress'),
1890+ 'percent_completed': fields.function(_get_percent_completed, method=True, string='% completed', type='integer', readonly=True),
1891+ 'message': fields.text(string='Message', readonly=True),
1892+ 'product_ids': fields.many2many('product.product', 'prod_mass_update_product_rel', 'product_id',
1893+ 'prod_mass_update_id', string="Product selection", order_by="default_code",
1894+ domain=[('expected_prod_creator', '=', 'True'), '|', ('active', '=', True), ('active', '=', False)]),
1895+ 'not_deactivated_product_ids': fields.one2many('product.mass.update.errors', 'p_mass_upd_id',
1896+ string="Product(s) that can not be deactivated"),
1897+ 'has_not_deactivable': fields.boolean(string='Document has non-deactivable product(s)', readonly=True),
1898+ # Fields
1899+ 'active_product': fields.selection(selection=[('no', 'No'), ('yes', 'Yes')], string='Active', help="If the active field is set to False, it allows to hide the nomenclature without removing it."),
1900+ 'dangerous_goods': fields.selection(selection=[('False', 'No'), ('True', 'Yes'), ('no_know', 'tbd')], string='Dangerous Goods'),
1901+ 'heat_sensitive_item': fields.selection(selection=[('False', 'No'), ('True', 'Yes'), ('no_know', 'tbd')], string='Temperature sensitive item'),
1902+ 'single_use': fields.selection(selection=[('no', 'No'), ('yes', 'Yes'), ('no_know', 'tbd')], string='Single Use'),
1903+ 'short_shelf_life': fields.selection(selection=[('False', 'No'), ('True', 'Yes'), ('no_know', 'tbd')], string='Short Shelf Life'),
1904+ 'alert_time': fields.char(string='Product Alert Time', size=32, help="The number of months after which an alert should be notified about the production lot."),
1905+ 'life_time': fields.char('Product Life Time', size=32, help='The number of months before a production lot may become dangerous and should not be consumed.'),
1906+ 'use_time': fields.char('Product Use Time', size=32, help='The number of months before a production lot starts deteriorating without becoming dangerous.'),
1907+ 'procure_delay': fields.char(string='Procurement Lead Time', size=32,
1908+ help='It\'s the default time to procure this product. This lead time will be used on the Order cycle procurement computation'),
1909+ 'procure_method': fields.selection([('make_to_stock', 'Make to Stock'), ('make_to_order', 'Make to Order')], 'Procurement Method',
1910+ help="If you encode manually a Procurement, you probably want to use a make to order method."),
1911+ 'product_state': fields.selection([('valid', 'Valid'), ('phase_out', 'Phase Out'), ('stopped', 'Stopped'), ('archived', 'Archived'), ('status1', 'Status 1'), ('status2', 'Status 2'), ], 'Status', help="Tells the user if he can use the product or not."),
1912+ 'sterilized': fields.selection(selection=[('no', 'No'), ('yes', 'Yes'), ('no_know', 'tbd')], string='Sterile'),
1913+ 'supply_method': fields.selection([('produce', 'Produce'), ('buy', 'Buy')], 'Supply Method',
1914+ help="Produce will generate production order or tasks, according to the product type. Purchase will trigger purchase orders when requested."),
1915+ 'seller_id': fields.many2one('res.partner', 'Default Partner'),
1916+ 'property_account_income': fields.many2one('account.account', string='Income Account',
1917+ help='This account will be used for invoices instead of the default one to value sales for the current product'),
1918+ 'property_account_expense': fields.many2one('account.account', string='Expense Account',
1919+ help='This account will be used for invoices instead of the default one to value expenses for the current product'),
1920+ 'empty_status': fields.boolean(string='Set Status as empty'),
1921+ 'empty_inc_account': fields.boolean(string='Set Income Account as empty'),
1922+ 'empty_exp_account': fields.boolean(string='Set Expense Account as empty'),
1923+ }
1924+
1925+ _defaults = {
1926+ 'state': 'draft',
1927+ 'import_in_progress': False,
1928+ 'message': '',
1929+ 'active_product': '',
1930+ 'dangerous_goods': '',
1931+ 'heat_sensitive_item': '',
1932+ 'single_use': '',
1933+ 'short_shelf_life': '',
1934+ 'procure_method': '',
1935+ 'sterilized': '',
1936+ 'supply_method': '',
1937+ }
1938+
1939+ def write(self, cr, user, ids, vals, context=None):
1940+ '''
1941+ override write method
1942+ '''
1943+ if context is None:
1944+ context = {}
1945+
1946+ if context.get('button') == 'dummy' and '__last_update' in context:
1947+ del context['__last_update']
1948+
1949+ if not ids:
1950+ return True
1951+
1952+ if 'empty_status' in vals and vals['empty_status']:
1953+ vals['product_state'] = ''
1954+ if 'empty_inc_account' in vals and vals['empty_inc_account']:
1955+ vals['property_account_income'] = False
1956+ if 'empty_exp_account' in vals and vals['empty_exp_account']:
1957+ vals['property_account_expense'] = False
1958+
1959+ return super(product_mass_update, self).write(cr, user, ids, vals, context)
1960+
1961+ def copy(self, cr, uid, id, default=None, context=None):
1962+ if context is None:
1963+ context = {}
1964+
1965+ if default is None:
1966+ default = {}
1967+
1968+ default.update({
1969+ 'user_id': False,
1970+ 'date_done': False,
1971+ 'message': '',
1972+ 'not_deactivated_product_ids': [(6, 0, [])],
1973+ 'has_not_deactivable': False,
1974+ 'empty_status': False,
1975+ 'empty_inc_account': False,
1976+ 'empty_exp_account': False,
1977+ })
1978+
1979+ return super(product_mass_update, self).copy(cr, uid, id, default=default, context=context)
1980+
1981+ def onchange_status_check(self, cr, uid, ids, empty_status):
1982+ if empty_status:
1983+ return {'value': {'product_state': ''}}
1984+ return {'value': {}}
1985+
1986+ def onchange_inc_check(self, cr, uid, ids, empty_inc_account):
1987+ if empty_inc_account:
1988+ return {'value': {'property_account_income': False}}
1989+ return {'value': {}}
1990+
1991+ def onchange_exp_check(self, cr, uid, ids, empty_exp_account):
1992+ if empty_exp_account:
1993+ return {'value': {'property_account_expense': False}}
1994+ return {'value': {}}
1995+
1996+ def cancel_update(self, cr, uid, ids, context=None):
1997+ '''
1998+ Delete the current Product Mass Update
1999+ '''
2000+ if context is None:
2001+ context = {}
2002+
2003+ self.unlink(cr, uid, ids, context=context)
2004+
2005+ return {
2006+ 'type': 'ir.actions.act_window',
2007+ 'res_model': 'product.mass.update',
2008+ 'view_type': 'form',
2009+ 'view_mode': 'tree,form',
2010+ 'target': 'crush',
2011+ }
2012+
2013+ def dummy(self, cr, uid, ids, context=None):
2014+ """
2015+ This button is only for updating the view.
2016+ """
2017+ if isinstance(ids, (int, long)):
2018+ ids = [ids]
2019+
2020+ return True
2021+
2022+ def reset_update(self, cr, uid, ids, context=None):
2023+ """
2024+ This button is only for resetting the update
2025+ """
2026+ if context is None:
2027+ context = {}
2028+
2029+ if isinstance(ids, (int, long)):
2030+ ids = [ids]
2031+
2032+ # Unlink existing errors
2033+ upd_errors_obj = self.pool.get('product.mass.update.errors')
2034+ errors_ids = upd_errors_obj.search(cr, uid, [('p_mass_upd_id', 'in', ids)], context=context)
2035+ upd_errors_obj.unlink(cr, uid, errors_ids, context=context)
2036+
2037+ vals = {
2038+ 'state': 'draft',
2039+ 'message': '',
2040+ 'has_not_deactivable': False,
2041+ }
2042+ self.write(cr, uid, ids, vals, context=context)
2043+
2044+ return True
2045+
2046+ def launch_update(self, cr, uid, ids, context=None):
2047+ '''
2048+ Launch a thread for update
2049+ '''
2050+ if not ids:
2051+ return True
2052+
2053+ data_obj = self.pool.get('ir.model.data')
2054+ p_state_obj = self.pool.get('product.status')
2055+
2056+ p_mass_upd = self.browse(cr, uid, ids[0], context=context)
2057+ if not p_mass_upd.product_ids:
2058+ raise osv.except_osv(_('Error'), _('You can not apply an update on no products.'))
2059+
2060+ vals = {}
2061+ if p_mass_upd.dangerous_goods:
2062+ vals.update({'dangerous_goods': p_mass_upd.dangerous_goods})
2063+ if p_mass_upd.heat_sensitive_item:
2064+ heat_attr = p_mass_upd.heat_sensitive_item == 'True' and 'heat_yes' or p_mass_upd.heat_sensitive_item == 'False' and 'heat_no' \
2065+ or p_mass_upd.heat_sensitive_item == 'tbd' and 'heat_no_know' or False
2066+ heat_id = data_obj.get_object_reference(cr, uid, 'product_attributes', heat_attr)[1]
2067+ if heat_id:
2068+ vals.update({'heat_sensitive_item': heat_id})
2069+ if p_mass_upd.short_shelf_life:
2070+ vals.update({'short_shelf_life': p_mass_upd.short_shelf_life})
2071+ if p_mass_upd.alert_time:
2072+ try:
2073+ alert_time = int(p_mass_upd.alert_time)
2074+ vals.update({'alert_time': alert_time})
2075+ except ValueError:
2076+ raise osv.except_osv(_('Error'), _('Alert Time must be an integer.'))
2077+ if p_mass_upd.life_time:
2078+ try:
2079+ life_time = int(p_mass_upd.life_time)
2080+ vals.update({'life_time': life_time})
2081+ except ValueError:
2082+ raise osv.except_osv(_('Error'), _('Life Time must be an integer.'))
2083+ if p_mass_upd.use_time:
2084+ try:
2085+ use_time = int(p_mass_upd.use_time)
2086+ vals.update({'use_time': use_time})
2087+ except ValueError:
2088+ raise osv.except_osv(_('Error'), _('Use Time must be an integer.'))
2089+ if p_mass_upd.procure_delay:
2090+ try:
2091+ procure_delay = float(p_mass_upd.procure_delay)
2092+ vals.update({'procure_delay': procure_delay})
2093+ except ValueError:
2094+ raise osv.except_osv(_('Error'), _('Procurement Lead Time must be a float.'))
2095+ if p_mass_upd.procure_method:
2096+ vals.update({'procure_method': p_mass_upd.procure_method})
2097+ if p_mass_upd.single_use:
2098+ vals.update({'single_use': p_mass_upd.single_use})
2099+ if p_mass_upd.product_state:
2100+ p_state_ids = p_state_obj.search(cr, uid, [('code', '=', p_mass_upd.product_state)], context=context)
2101+ if p_state_ids:
2102+ vals.update({'state': p_state_ids[0]})
2103+ elif p_mass_upd.empty_status:
2104+ vals.update({'state': False})
2105+ if p_mass_upd.sterilized:
2106+ vals.update({'sterilized': p_mass_upd.sterilized})
2107+ if p_mass_upd.supply_method:
2108+ vals.update({'supply_method': p_mass_upd.supply_method})
2109+ if p_mass_upd.property_account_income:
2110+ vals.update({'property_account_income': p_mass_upd.property_account_income.id})
2111+ elif p_mass_upd.empty_inc_account:
2112+ vals.update({'property_account_income': False})
2113+ if p_mass_upd.property_account_expense:
2114+ vals.update({'property_account_expense': p_mass_upd.property_account_expense.id})
2115+ elif p_mass_upd.empty_exp_account:
2116+ vals.update({'property_account_expense': False})
2117+
2118+ thread = threading.Thread(target=self.apply_update, args=(cr, uid, ids, vals, context))
2119+ thread.start()
2120+
2121+ msg_to_return = _("Update in progress, please leave this window open and press the button 'Update' when you think that the update is done. Otherwise, you can continue to use Unifield.")
2122+ return self.write(cr, uid, ids, {'message': msg_to_return, 'state': 'in_progress'}, context=context)
2123+
2124+ def apply_update(self, cr, uid, ids, vals, context=None):
2125+ '''
2126+ Apply the current Product Mass Update
2127+ '''
2128+ if context is None:
2129+ context = {}
2130+
2131+ # New cursor
2132+ cr = pooler.get_db(cr.dbname).cursor()
2133+
2134+ prod_obj = self.pool.get('product.product')
2135+ p_suppinfo_obj = self.pool.get('product.supplierinfo')
2136+ upd_progress_obj = self.pool.get('product.mass.update.progressbar')
2137+ upd_errors_obj = self.pool.get('product.mass.update.errors')
2138+
2139+ p_mass_upd = self.browse(cr, uid, ids[0], context=context)
2140+ try:
2141+ # For the progress bar
2142+ upd_progress_ids = upd_progress_obj.search(cr, uid, [('p_mass_upd_id', '=', p_mass_upd.id)], context=context)
2143+ if upd_progress_ids:
2144+ upd_progress_id = upd_progress_ids[0]
2145+ else:
2146+ upd_progress_id = upd_progress_obj.create(cr, uid, {'p_mass_upd_id': p_mass_upd.id}, context=context)
2147+
2148+ num_prod = 0
2149+ not_deactivated = []
2150+ for prod in p_mass_upd.product_ids:
2151+ # Check procurement method
2152+ if p_mass_upd.procure_method and prod.type in ('consu', 'service', 'service_recep') and \
2153+ p_mass_upd.procure_method != 'make_to_order':
2154+ raise osv.except_osv(_('Error'), _('You must select on order procurement method for %s products.')
2155+ % (prod.type == 'consu' and 'Non-stockable' or 'Service'))
2156+ # Deactivation
2157+ if p_mass_upd.seller_id and not p_suppinfo_obj.search(cr, uid, [('product_id', '=', prod.id), ('name', '=', p_mass_upd.seller_id.id)], context=context):
2158+ p_suppinfo_obj.create(cr, uid, {'product_id': prod.id, 'name': p_mass_upd.seller_id.id, 'sequence': 1}, context=context)
2159+ if p_mass_upd.active_product:
2160+ if not prod.active and p_mass_upd.active_product == 'yes':
2161+ prod_obj.reactivate_product(cr, uid, [prod.id], context=context)
2162+ elif prod.active and p_mass_upd.active_product == 'no':
2163+ deactivated = prod_obj.deactivate_product(cr, uid, [prod.id], context=context)
2164+ if deactivated != True: # If doesn't return True, the product has not been deactivated
2165+ not_deactivated.append(deactivated.get('res_id'))
2166+ num_prod += 1
2167+ percent_completed = float(num_prod) / float(len(p_mass_upd.product_ids)) * 100.0
2168+ upd_progress_obj.write(cr, uid, upd_progress_id, {'percent_completed': percent_completed}, context=context)
2169+
2170+ if not_deactivated:
2171+ cr.rollback() # Rollback deactivation and product seller creation
2172+ for wiz_prod_error in self.pool.get('product.deactivation.error').browse(cr, uid, not_deactivated):
2173+ err_vals = {
2174+ 'p_mass_upd_id': p_mass_upd.id,
2175+ 'product_id': wiz_prod_error.product_id.id,
2176+ 'stock_exist': wiz_prod_error.stock_exist,
2177+ 'open_documents': wiz_prod_error.error_lines and ', '.join([x.doc_ref for x in wiz_prod_error.error_lines if x.doc_ref]) or '',
2178+ }
2179+ upd_errors_obj.create(cr, uid, err_vals, context=context)
2180+
2181+ p_mass_upd_vals = {
2182+ 'has_not_deactivable': True,
2183+ 'message': _('Some products could not be deactivated. No product will be changed until all of them can be deactivated. Please check the corresponding tab.'),
2184+ 'state': 'error',
2185+ }
2186+ self.write(cr, uid, p_mass_upd.id, p_mass_upd_vals, context=context)
2187+ else:
2188+ prod_obj.write(cr, uid, [prod.id for prod in p_mass_upd.product_ids], vals, context=context)
2189+ user_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).id
2190+
2191+ # Unlink existing errors
2192+ errors_ids = upd_errors_obj.search(cr, uid, [('p_mass_upd_id', '=', p_mass_upd.id)], context=context)
2193+ upd_errors_obj.unlink(cr, uid, errors_ids, context=context)
2194+
2195+ p_mass_upd_vals = {
2196+ 'has_not_deactivable': False,
2197+ 'date_done': time.strftime('%Y-%m-%d %H:%M'),
2198+ 'user_id': user_id,
2199+ 'state': 'done',
2200+ }
2201+ self.write(cr, uid, p_mass_upd.id, p_mass_upd_vals, context=context)
2202+ except Exception as e:
2203+ err = _('An error has occured during the update:\n%s') % tools.ustr(e.value or e)
2204+ self.write(cr, uid, p_mass_upd.id, {'state': 'error', 'message': err}, context=context)
2205+ finally:
2206+ cr.commit()
2207+ cr.close(True)
2208+
2209+ return True
2210+
2211+ def wizard_import_products(self, cr, uid, ids, context=None):
2212+ '''
2213+ Launches the wizard to import lines from a file
2214+ '''
2215+ if context is None:
2216+ context = {}
2217+ if isinstance(ids, (int, long)):
2218+ ids = [ids]
2219+ context.update({'active_id': ids[0]})
2220+ columns_header = [(_(f[0]), f[1]) for f in columns_header_for_product_line_import]
2221+ default_template = SpreadsheetCreator('Template of import', columns_header, [])
2222+ file = base64.encodestring(default_template.get_xml(default_filters=['decode.utf8']))
2223+ export_id = self.pool.get('wizard.import.product.line').create(cr, uid, {
2224+ 'file': file,
2225+ 'filename_template': 'template.xls',
2226+ 'filename': 'Lines_Not_Imported.xls',
2227+ 'message': """%s %s""" % (_(GENERIC_MESSAGE), ', '.join([_(f) for f in columns_for_product_line_import]), ),
2228+ 'product_mass_upd_id': ids[0],
2229+ 'state': 'draft',
2230+ }, context)
2231+
2232+ return {
2233+ 'type': 'ir.actions.act_window',
2234+ 'res_model': 'wizard.import.product.line',
2235+ 'res_id': export_id,
2236+ 'view_type': 'form',
2237+ 'view_mode': 'form',
2238+ 'target': 'crush',
2239+ 'context': context,
2240+ }
2241+
2242+ def export_product_errors(self, cr, uid, ids, context=None):
2243+ return {
2244+ 'type': 'ir.actions.report.xml',
2245+ 'report_name': 'product_mass_update_export_xls',
2246+ 'datas': {'ids': ids, 'target_filename': _('Product Mass Update Errors')},
2247+ 'nodestroy': True,
2248+ 'context': context,
2249+ }
2250+
2251+
2252+product_mass_update()
2253+
2254+
2255+class product_mass_update_progressbar(osv.osv_memory):
2256+ _name = 'product.mass.update.progressbar'
2257+ _description = 'Product Mass Update Progress Bar'
2258+
2259+ _columns = {
2260+ 'p_mass_upd_id': fields.many2one('product.mass.update', 'Product Mass Update'),
2261+ 'percent_completed': fields.integer(string='% completed', readonly=True),
2262+ }
2263+
2264+ _default = {
2265+ 'p_mass_upd_id': False,
2266+ 'percent_completed': 0,
2267+ }
2268+
2269+
2270+product_mass_update_progressbar()
2271+
2272+
2273+class product_mass_update_errors(osv.osv):
2274+ _name = 'product.mass.update.errors'
2275+ _description = 'Product Mass Update Errors'
2276+
2277+ _order = 'product_id'
2278+
2279+ _columns = {
2280+ 'p_mass_upd_id': fields.many2one('product.mass.update', 'Product Mass Update', ondelete='cascade'),
2281+ 'product_id': fields.many2one('product.product', string='Product', required=True),
2282+ 'stock_exist': fields.boolean(string='Stock Exist'),
2283+ 'open_documents': fields.char(string='Open Documents', size=256),
2284+ }
2285+
2286+ _default = {
2287+ 'stock_exist': False,
2288+ 'open_documents': '',
2289+ }
2290+
2291+
2292+product_mass_update_errors()
2293
2294=== added file 'bin/addons/product/wizard/product_mass_update_view.xml'
2295--- bin/addons/product/wizard/product_mass_update_view.xml 1970-01-01 00:00:00 +0000
2296+++ bin/addons/product/wizard/product_mass_update_view.xml 2019-04-15 13:13:32 +0000
2297@@ -0,0 +1,139 @@
2298+<?xml version="1.0" encoding="utf-8"?>
2299+<openerp>
2300+ <data>
2301+ <!-- Views -->
2302+ <record id="view_product_mass_update_form" model="ir.ui.view">
2303+ <field name="name">product.mass.update.form</field>
2304+ <field name="model">product.mass.update</field>
2305+ <field name="type">form</field>
2306+ <field name="arch" type="xml">
2307+ <form string="Product Mass Update" hide_delete_button="1" >
2308+ <field name="name" attrs="{'readonly': [('state', '!=', 'draft')]}" />
2309+ <group string=" New Data " colspan="4" attrs="{'readonly': [('state', '!=', 'draft')]}">
2310+ <field name="active_product" />
2311+ <field name="dangerous_goods" />
2312+ <field name="heat_sensitive_item" />
2313+ <field name="single_use" />
2314+ <field name="short_shelf_life" />
2315+ <field name="alert_time" />
2316+ <field name="life_time" />
2317+ <field name="use_time" />
2318+ <field name="procure_delay" />
2319+ <field name="procure_method" />
2320+ <group colspan="2">
2321+ <field name="product_state" attrs="{'readonly':['|', ('empty_status', '=', True), ('state', '!=', 'draft')]}" />
2322+ <field name="empty_status" on_change="onchange_status_check(empty_status)" />
2323+ </group>
2324+ <field name="sterilized" />
2325+ <field name="supply_method" />
2326+ <field name="seller_id" />
2327+ <group colspan="2">
2328+ <field name="property_account_income" attrs="{'readonly':['|', ('empty_inc_account', '=', True), ('state', '!=', 'draft')]}"
2329+ domain="[('type','&lt;&gt;','view'), ('type','&lt;&gt;','consolidation'),
2330+ ('user_type_code', 'in', ['expense', 'income', 'asset']),
2331+ ('user_type_name', '&lt;&gt;', 'Extra-accounting expenses')]"/>
2332+ <field name="empty_inc_account" on_change="onchange_inc_check(empty_inc_account)" />
2333+ </group>
2334+ <group colspan="2">
2335+ <field name="property_account_expense" attrs="{'readonly':['|', ('empty_exp_account', '=', True), ('state', '!=', 'draft')]}"
2336+ domain="[('type','&lt;&gt;','view'), ('type','&lt;&gt;','consolidation'),
2337+ ('user_type_code', 'in', ['expense', 'income', 'asset']),
2338+ ('user_type_name', '&lt;&gt;', 'Extra-accounting expenses')]"/>
2339+ <field name="empty_exp_account" on_change="onchange_exp_check(empty_exp_account)" />
2340+ </group>
2341+ </group>
2342+ <field name="has_not_deactivable" invisible="1" />
2343+ <group colspan="4" attrs="{'invisible':[('has_not_deactivable', '=', False), ('state', 'not in', ['in_progress', 'error'])]}">
2344+ <html>
2345+ <style>
2346+ #prod_mass_upd_error p, #prod_mass_upd_error span, #prod_mass_upd_error textarea {
2347+ text-align: center;
2348+ v-align: middle;
2349+ color: red;
2350+ font-weight: bold;
2351+ font-size: 1.2em;
2352+ resize: None;
2353+ }
2354+ </style>
2355+ <div id="prod_mass_upd_error">
2356+ <field name="message" colspan="4" nolabel="1" />
2357+ </div>
2358+ </html>
2359+ </group>
2360+ <group colspan="4">
2361+ <field name="percent_completed" widget="progressbar" colspan="2" attrs="{'invisible':[('state', 'not in', ['in_progress', 'done'])]}"/>
2362+ <button name="dummy" string="Update" icon="gtk-execute" colspan="2" type="object" attrs="{'invisible':[('state', '!=', 'in_progress')]}"/>
2363+ <button name="reset_update" string="Reset Update" icon="gtk-undo" colspan="2" type="object" attrs="{'invisible':[('state', '!=', 'error')]}"/>
2364+ </group>
2365+ <notebook>
2366+ <page string="Products">
2367+ <group name="import" string=" Import Lines " colspan="4" attrs="{'invisible':[('state', '!=', 'draft')]}">
2368+ <button name="wizard_import_products" string="Import products" icon="gtk-dnd" colspan="2" type="object"/>
2369+ </group>
2370+ <field name="product_ids" colspan="4" nolabel="1" attrs="{'readonly': [('state', '!=', 'draft')]}" domain="[('active', 'in', ['t', 'f'])]">
2371+ <tree string="Products" hide_edit_button="1" colors="grey:active == False">
2372+ <field name="default_code" />
2373+ <field name="name" />
2374+ <field name="active" invisible="1" />
2375+ </tree>
2376+ </field>
2377+ </page>
2378+ <page string="Non-Deactivable Products" attrs="{'invisible': [('has_not_deactivable', '=', False)]}">
2379+ <button name="export_product_errors" string="Export Product List" icon="gtk-execute" colspan="4" type="object" />
2380+ <field name="not_deactivated_product_ids" colspan="4" nolabel="1" readonly="1">
2381+ <tree string="Products" noteditable="1">
2382+ <field name="product_id" />
2383+ <field name="stock_exist" />
2384+ <field name="open_documents" />
2385+ </tree>
2386+ </field>
2387+ </page>
2388+ </notebook>
2389+ <group colspan="4">
2390+ <field name="state" colspan="2" />
2391+ <button name="cancel_update" string="Delete Update" icon="gtk-cancel" colspan="1" type="object" attrs="{'invisible':[('state', '!=', 'draft')]}"/>
2392+ <button name="launch_update" string="Apply Update" icon="gtk-go-forward" colspan="1" type="object" attrs="{'invisible': [('state', '!=', 'draft')]}"/>
2393+ </group>
2394+ </form>
2395+ </field>
2396+ </record>
2397+
2398+ <record id="view_product_mass_update_tree" model="ir.ui.view">
2399+ <field name="name">product.mass.update.tree</field>
2400+ <field name="model">product.mass.update</field>
2401+ <field name="type">tree</field>
2402+ <field name="arch" type="xml">
2403+ <tree string="Product Mass Update" noteditable="state!='draft'" hide_delete_button="1" colors="blue:state in ('draft');red:state in ('error')">
2404+ <field name="name"/>
2405+ <field name="product_ids"/>
2406+ <field name="date_done"/>
2407+ <field name="user_id"/>
2408+ <field name="state"/>
2409+ </tree>
2410+ </field>
2411+ </record>
2412+
2413+ <record id="view_product_mass_update_search" model="ir.ui.view">
2414+ <field name="name">product.mass.update.search</field>
2415+ <field name="model">product.mass.update</field>
2416+ <field name="type">search</field>
2417+ <field name="arch" type="xml">
2418+ <search string="Product Mass Update">
2419+ <field name="name"/>
2420+ <field name="date_done"/>
2421+ <field name="user_id"/>
2422+ <field name="state"/>
2423+ </search>
2424+ </field>
2425+ </record>
2426+
2427+ <!-- Menu -->
2428+ <record id="previous_mass_update_action" model="ir.actions.act_window">
2429+ <field name="name">Product Mass Update</field>
2430+ <field name="res_model">product.mass.update</field>
2431+ <field name="view_type">form</field>
2432+ <field name="view_id" ref="view_product_mass_update_tree"/>
2433+ <field name="context">{}</field>
2434+ </record>
2435+ </data>
2436+</openerp>
2437
2438=== modified file 'bin/addons/product_attributes/product_attributes_view.xml'
2439--- bin/addons/product_attributes/product_attributes_view.xml 2019-02-11 10:03:13 +0000
2440+++ bin/addons/product_attributes/product_attributes_view.xml 2019-04-15 13:13:32 +0000
2441@@ -11,7 +11,7 @@
2442 <field name="arch" type="xml">
2443 <data>
2444 <xpath expr="/tree" position="replace">
2445- <tree colors="red:virtual_available&lt;0;blue:virtual_available&gt;=0 and state in ('draft', 'end', 'obsolete');black:virtual_available&gt;=0 and state not in ('draft', 'end', 'obsolete')" string="Products">
2446+ <tree colors="red:virtual_available&lt;0;blue:virtual_available&gt;=0 and state in ('draft', 'end', 'obsolete');grey:active == False" string="Products">
2447 <field name="default_code" string="Code"/>
2448 <field name="name" string="Description"/>
2449 <field name="categ_id" invisible="1"/>
2450@@ -28,6 +28,7 @@
2451 <field name="international_status"/>
2452 <field name="uf_create_date" string="Creation"/>
2453 <field name="uf_write_date" string="Modification"/>
2454+ <field name="active" invisible="1"/>
2455 </tree>
2456 </xpath>
2457 </data>
2458@@ -821,5 +822,9 @@
2459 </field>
2460 </record>
2461
2462+ <!-- Product Mass Update Menu -->
2463+ <menuitem id="product.parent_product_mass_update" parent="product_attributes.menu_main_product" name="Products Update" />
2464+ <menuitem action="product.previous_mass_update_action" id="menu_import_request" sequence="1" parent="product.parent_product_mass_update" />
2465+
2466 </data>
2467 </openerp>

Subscribers

People subscribed via source and target branches