Merge lp:~dorian-kemps/unifield-server/US-1080 into lp:unifield-server
- US-1080
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+360164@code.launchpad.net |
Commit message
Description of the change
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','<>','view'), ('type','<>','consolidation'), |
2330 | + ('user_type_code', 'in', ['expense', 'income', 'asset']), |
2331 | + ('user_type_name', '<>', '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','<>','view'), ('type','<>','consolidation'), |
2337 | + ('user_type_code', 'in', ['expense', 'income', 'asset']), |
2338 | + ('user_type_name', '<>', '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<0;blue:virtual_available>=0 and state in ('draft', 'end', 'obsolete');black:virtual_available>=0 and state not in ('draft', 'end', 'obsolete')" string="Products"> |
2446 | + <tree colors="red:virtual_available<0;blue:virtual_available>=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> |