~unifield-team/unifield-wm/us-826

« back to all changes in this revision

Viewing changes to msf_doc_import/tender.py

  • Committer: Olivier DOSSMANN
  • Date: 2014-03-31 09:31:46 UTC
  • mto: This revision was merged to the branch mainline in revision 2086.
  • Revision ID: od@tempo-consulting.fr-20140331093146-tgvxnly1kc1hbv1s
UF-2171 [ADD] Analytic distribution reset button for recurring models

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
##############################################################################
 
3
#
 
4
#    OpenERP, Open Source Management Solution
 
5
#    Copyright (C) 2012 TeMPO Consulting, MSF. All Rights Reserved
 
6
#
 
7
#    This program is free software: you can redistribute it and/or modify
 
8
#    it under the terms of the GNU Affero General Public License as
 
9
#    published by the Free Software Foundation, either version 3 of the
 
10
#    License, or (at your option) any later version.
 
11
#
 
12
#    This program is distributed in the hope that it will be useful,
 
13
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
#    GNU Affero General Public License for more details.
 
16
#
 
17
#    You should have received a copy of the GNU Affero General Public License
 
18
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
#
 
20
##############################################################################
 
21
 
 
22
from osv import osv
 
23
from osv import fields
 
24
from tools.translate import _
 
25
import base64
 
26
from msf_doc_import import GENERIC_MESSAGE
 
27
# import below commented in utp-1344: becomes useless as the import is done in wizard
 
28
#from spreadsheet_xml.spreadsheet_xml import SpreadsheetXML
 
29
#import check_line
 
30
#from msf_doc_import import MAX_LINES_NB
 
31
from spreadsheet_xml.spreadsheet_xml_write import SpreadsheetCreator
 
32
from msf_doc_import.wizard import TENDER_COLUMNS_HEADER_FOR_IMPORT as columns_header_for_tender_line_import
 
33
from msf_doc_import import GENERIC_MESSAGE
 
34
from msf_doc_import.wizard import TENDER_COLUMNS_FOR_IMPORT as columns_for_tender_line_import
 
35
 
 
36
 
 
37
class tender(osv.osv):
 
38
    _inherit = 'tender'
 
39
 
 
40
    def get_bool_values(self, cr, uid, ids, fields, arg, context=None):
 
41
        res = {}
 
42
        if isinstance(ids, (int, long)):
 
43
            ids = [ids]
 
44
        for obj in self.browse(cr, uid, ids, context=context):
 
45
            res[obj.id] = False
 
46
            if any([item for item in obj.tender_line_ids  if item.to_correct_ok]):
 
47
                res[obj.id] = True
 
48
        return res
 
49
 
 
50
    _columns = {
 
51
# The field below were replaced by the wizard_import_fo_line (utp-113)
 
52
#        'file_to_import': fields.binary(string='File to import',
 
53
#                                        help="""* You can use the template of the export for the format that you need to use.
 
54
#                                                * The file should be in XML Spreadsheet 2003 format.
 
55
#                                                * You can import up to %s lines each time,
 
56
#                                                else you have to split the lines in several files and import each one by one.
 
57
#                                                """ % MAX_LINES_NB),
 
58
        'hide_column_error_ok': fields.function(get_bool_values, method=True, type="boolean", string="Show column errors", store=False),
 
59
    }
 
60
    
 
61
    def _check_active_product(self, cr, uid, ids, context=None):
 
62
        '''
 
63
        Check if the tender contains a line with an inactive products
 
64
        '''
 
65
        inactive_lines = self.pool.get('tender.line').search(cr, uid, [('product_id.active', '=', False),
 
66
                                                                       ('tender_id', 'in', ids),
 
67
                                                                       ('tender_id.state', 'not in', ['draft', 'cancel', 'done'])], context=context)
 
68
        
 
69
        if inactive_lines:
 
70
            plural = len(inactive_lines) == 1 and _('A product has') or _('Some products have')
 
71
            l_plural = len(inactive_lines) == 1 and _('line') or _('lines')          
 
72
            raise osv.except_osv(_('Error'), _('%s been inactivated. If you want to generate RfQ from this document you have to remove/correct the line containing those inactive products (see red %s of the document)') % (plural, l_plural))
 
73
            return False
 
74
        return True
 
75
    
 
76
    _constraints = [
 
77
        (_check_active_product, "You cannot validate this tender because it contains a line with an inactive product", ['tender_line_ids', 'state'])
 
78
    ]
 
79
 
 
80
# UTP-113 THE METHOD BELOW WAS RETAKEN IN THE WIZARD
 
81
#    def import_file(self, cr, uid, ids, context=None):
 
82
#        '''
 
83
#        Import lines from Excel file (in xml)
 
84
#        '''
 
85
#        if not context:
 
86
#            context = {}
 
87
#        if isinstance(ids, (int, long)):
 
88
#            ids = [ids]
 
89
#        product_obj = self.pool.get('product.product')
 
90
#        uom_obj = self.pool.get('product.uom')
 
91
#        obj_data = self.pool.get('ir.model.data')
 
92
#        tender_line_obj = self.pool.get('tender.line')
 
93
#        view_id = obj_data.get_object_reference(cr, uid, 'tender_flow', 'tender_form')[1]
 
94
#        vals = {}
 
95
#        vals['tender_line_ids'] = []
 
96
#        obj = self.browse(cr, uid, ids, context=context)[0]
 
97
#        if not obj.file_to_import:
 
98
#            raise osv.except_osv(_('Error'), _('Nothing to import.'))
 
99
#        fileobj = SpreadsheetXML(xmlstring=base64.decodestring(obj.file_to_import))
 
100
#        # check that the max number of lines is not excedeed
 
101
#        if check_nb_of_lines(fileobj=fileobj):
 
102
#            raise osv.except_osv(_('Warning !'), _("""You can\'t have more than %s lines in your file.""") % MAX_LINES_NB)
 
103
#        # iterator on rows
 
104
#        rows = fileobj.getRows()
 
105
#        # ignore the first row
 
106
#        line_num = 1
 
107
#        rows.next()
 
108
#        to_write = {}
 
109
#        for row in rows:
 
110
#            # default values
 
111
#            nb_lines_error = 0
 
112
#            to_write = {
 
113
#                'error_list': [],
 
114
#                'warning_list': [],
 
115
#                'to_correct_ok': False,
 
116
#                'default_code': obj_data.get_object_reference(cr, uid, 'msf_doc_import', 'product_tbd')[1],
 
117
#                'uom_id': obj_data.get_object_reference(cr, uid, 'msf_doc_import', 'uom_tbd')[1],
 
118
#                'product_qty': 1,
 
119
#            }
 
120
#            line_num += 1
 
121
#            col_count = len(row)
 
122
#            if col_count != 6:
 
123
#                raise osv.except_osv(_('Error'), _(""" Tenders should have exactly 6 columns in this order:
 
124
#Product Code*, Product Description*, Quantity*, Product UoM*, Unit Price*, Delivery Requested Date*"""))
 
125
#            try:
 
126
#                if not check_empty_line(row=row, col_count=col_count):
 
127
#                    continue
 
128
#                # for each cell we check the value
 
129
#                # Cell 0: Product Code
 
130
#                p_value = {}
 
131
#                p_value = product_value(cr, uid, obj_data=obj_data, product_obj=product_obj, row=row, to_write=to_write, context=context)
 
132
#                to_write.update({'product_id': p_value['default_code'], 'error_list': p_value['error_list']})
 
133
#
 
134
#                # Cell 2: Quantity
 
135
#                qty_value = {}
 
136
#                qty_value = quantity_value(product_obj=product_obj, row=row, to_write=to_write, context=context)
 
137
#                to_write.update({'qty': qty_value['product_qty'], 'error_list': qty_value['error_list'], 'warning_list': qty_value['warning_list']})
 
138
#
 
139
#                # Cell 3: UoM
 
140
#                uom_value = {}
 
141
#                uom_value = compute_uom_value(cr, uid, obj_data=obj_data, product_obj=product_obj, uom_obj=uom_obj, row=row, to_write=to_write, context=context)
 
142
#                to_write.update({'product_uom': uom_value['uom_id'], 'error_list': uom_value['error_list']})
 
143
#
 
144
#                to_write.update({
 
145
#                    'to_correct_ok': [True for x in to_write['error_list']],  # the lines with to_correct_ok=True will be red
 
146
#                    'text_error': '\n'.join(to_write['error_list']),
 
147
#                    'tender_id': obj.id,
 
148
#                })
 
149
#                # we check consistency of uom and product values
 
150
#                tender_line_obj.check_data_for_uom(cr, uid, ids, to_write=to_write, context=context)
 
151
#                vals['tender_line_ids'].append((0, 0, to_write))
 
152
#            except IndexError:
 
153
#                print "The line num %s in the Excel file got element outside the defined 6 columns" % line_num
 
154
#
 
155
#        # write tender line on tender
 
156
#        context['import_in_progress'] = True
 
157
#        self.write(cr, uid, ids, vals, context=context)
 
158
#        nb_lines_error = self.pool.get('tender.line').search_count(cr, uid, [('to_correct_ok', '=', True),
 
159
#                                                                             ('tender_id', '=', ids[0])], context=context)
 
160
#        # log message
 
161
#        msg_to_return = get_log_message(to_write=to_write, tender=True, nb_lines_error=nb_lines_error)
 
162
#        if msg_to_return:
 
163
#            self.log(cr, uid, obj.id, _(msg_to_return), context={'view_id': view_id})
 
164
#        return True
 
165
 
 
166
    def wizard_import_tender_line(self, cr, uid, ids, context=None):
 
167
        '''
 
168
        Launches the wizard to import lines from a file
 
169
        '''
 
170
        if context is None:
 
171
            context = {}
 
172
        if isinstance(ids, (int, long)):
 
173
            ids = [ids]
 
174
        context.update({'active_id': ids[0]})
 
175
        columns_header = [(_(f[0]), f[1]) for f in columns_header_for_tender_line_import]
 
176
        default_template = SpreadsheetCreator('Template of import', columns_header, [])
 
177
        file = base64.encodestring(default_template.get_xml(default_filters=['decode.utf8']))
 
178
        export_id = self.pool.get('wizard.import.tender.line').create(cr, uid, {'file': file,
 
179
                                                                                'filename_template': 'template.xls',
 
180
                                                                                'message': """%s %s"""  % (GENERIC_MESSAGE, ', '.join([_(f) for f in columns_for_tender_line_import]), ),
 
181
                                                                                'filename': 'Lines_Not_Imported.xls',
 
182
                                                                                'tender_id': ids[0],
 
183
                                                                                'state': 'draft',}, context)
 
184
        return {'type': 'ir.actions.act_window',
 
185
                'res_model': 'wizard.import.tender.line',
 
186
                'res_id': export_id,
 
187
                'view_type': 'form',
 
188
                'view_mode': 'form',
 
189
                'target': 'crush',
 
190
                'context': context,
 
191
                }
 
192
 
 
193
    def check_lines_to_fix(self, cr, uid, ids, context=None):
 
194
        if isinstance(ids, (int, long)):
 
195
            ids = [ids]
 
196
        for var in self.browse(cr, uid, ids, context=context):
 
197
            if var.tender_line_ids:
 
198
                for var in var.tender_line_ids:
 
199
                    if var.to_correct_ok:
 
200
                        raise osv.except_osv(_('Warning !'), _('You still have lines to correct: check the red lines'))
 
201
        return True
 
202
 
 
203
tender()
 
204
 
 
205
 
 
206
class tender_line(osv.osv):
 
207
    '''
 
208
    override of tender_line class
 
209
    '''
 
210
    _inherit = 'tender.line'
 
211
    _description = 'Tender Line'
 
212
    
 
213
    def _get_inactive_product(self, cr, uid, ids, field_name, args, context=None):
 
214
        '''
 
215
        Fill the error message if the product of the line is inactive
 
216
        '''
 
217
        res = {}
 
218
        for line in self.browse(cr, uid, ids, context=context):
 
219
            res[line.id] = {'inactive_product': False,
 
220
                            'inactive_error': ''}
 
221
            if line.to_correct_ok:
 
222
                res[line.id].update({'inactive_error': line.text_error})
 
223
            if line.tender_id and line.tender_id.state not in ('cancel', 'done') and line.product_id and not line.product_id.active:
 
224
                res[line.id] = {'inactive_product': True,
 
225
                                'inactive_error': _('The product in line is inactive !')}
 
226
                
 
227
        return res    
 
228
    
 
229
    _columns = {
 
230
        'to_correct_ok': fields.boolean('To correct'),
 
231
        'text_error': fields.text('Errors'),
 
232
        'inactive_product': fields.function(_get_inactive_product, method=True, type='boolean', string='Product is inactive', store=False, multi='inactive'),
 
233
        'inactive_error': fields.function(_get_inactive_product, method=True, type='char', string='Error', store=False, multi='inactive'),
 
234
    }
 
235
    
 
236
    _defaults = {
 
237
        'inactive_product': False,
 
238
        'inactive_error': lambda *a: '',
 
239
    }
 
240
    
 
241
    def check_data_for_uom(self, cr, uid, ids, *args, **kwargs):
 
242
        context = kwargs['context']
 
243
        if context is None:
 
244
            context = {}
 
245
        if isinstance(ids, (int, long)):
 
246
            ids = [ids]
 
247
        obj_data = self.pool.get('ir.model.data')
 
248
        # we take the values that we are going to write in SO line in "to_write"
 
249
        to_write = kwargs['to_write']
 
250
        text_error = to_write['text_error']
 
251
        product_id = to_write['product_id']
 
252
        uom_id = to_write['product_uom']
 
253
        if uom_id and product_id:
 
254
            product_obj = self.pool.get('product.product')
 
255
            uom_obj = self.pool.get('product.uom')
 
256
            product = product_obj.browse(cr, uid, product_id, context=context)
 
257
            uom = uom_obj.browse(cr, uid, uom_id, context=context)
 
258
            if product.uom_id.category_id.id != uom.category_id.id:
 
259
                # this is inspired by onchange_uom in specific_rules>specific_rules.py
 
260
                text_error += _("""The product UOM must be in the same category than the UOM of the product.
 
261
The category of the UoM of the product is '%s' whereas the category of the UoM you have chosen is '%s'.
 
262
                """) % (product.uom_id.category_id.name, uom.category_id.name)
 
263
                return to_write.update({'text_error': text_error,
 
264
                                        'to_correct_ok': True})
 
265
        elif not uom_id or uom_id == obj_data.get_object_reference(cr, uid, 'msf_doc_import', 'uom_tbd')[1] and product_id:
 
266
            # we take the default uom of the product
 
267
            product_uom = product.uom_id.id
 
268
            return to_write.update({'product_uom': product_uom})
 
269
        elif not uom_id or uom_id == obj_data.get_object_reference(cr, uid, 'msf_doc_import', 'uom_tbd')[1]:
 
270
            # this is inspired by the on_change in purchase>purchase.py: product_uom_change
 
271
            text_error += _("\n The UoM was not defined so we set the price unit to 0.0.")
 
272
            return to_write.update({'text_error': text_error,
 
273
                                    'to_correct_ok': True,
 
274
                                    'price_unit': 0.0, })
 
275
 
 
276
    def onchange_uom(self, cr, uid, ids, product_id, product_uom, product_qty=0.00, context=None):
 
277
        '''
 
278
        Check if the UoM is convertible to product standard UoM
 
279
        '''
 
280
        warning = {}
 
281
        if product_uom and product_id:
 
282
            product_obj = self.pool.get('product.product')
 
283
            uom_obj = self.pool.get('product.uom')
 
284
            product = product_obj.browse(cr, uid, product_id, context=context)
 
285
            uom = uom_obj.browse(cr, uid, product_uom, context=context)
 
286
            if not self.pool.get('uom.tools').check_uom(cr, uid, product_id, product_uom, context):
 
287
                return {'warning': {'title': _('Wrong Product UOM !'),
 
288
                                    'message': _("You have to select a product UOM in the same category than the purchase UOM of the product")}}
 
289
        return self.onchange_uom_qty(cr, uid, ids, product_uom, product_qty)
 
290
 
 
291
    def write(self, cr, uid, ids, vals, context=None):
 
292
        if isinstance(ids, (int, long)):
 
293
            ids = [ids]
 
294
        if context is None:
 
295
            context = {}
 
296
        if not context.get('import_in_progress') and not context.get('button'):
 
297
            obj_data = self.pool.get('ir.model.data')
 
298
            tbd_uom = obj_data.get_object_reference(cr, uid, 'msf_doc_import', 'uom_tbd')[1]
 
299
            tbd_product = obj_data.get_object_reference(cr, uid, 'msf_doc_import', 'product_tbd')[1]
 
300
            message = ''
 
301
            if vals.get('product_uom'):
 
302
                if vals.get('product_uom') == tbd_uom:
 
303
                    message += _('You have to define a valid UOM, i.e. not "To be define".')
 
304
            if vals.get('product_id'):
 
305
                if vals.get('product_id') == tbd_product:
 
306
                    message += _('You have to define a valid product, i.e. not "To be define".')
 
307
            if vals.get('product_uom') and vals.get('product_id'):
 
308
                product_id = vals.get('product_id')
 
309
                product_uom = vals.get('product_uom')
 
310
                res = self.onchange_uom(cr, uid, ids, product_id, product_uom, vals.get('product_qty', 0.00), context)
 
311
                if res and res['warning']:
 
312
                    message += res['warning']['message']
 
313
            if message:
 
314
                raise osv.except_osv(_('Warning !'), _(message))
 
315
            else:
 
316
                vals['to_correct_ok'] = False
 
317
                vals['text_error'] = False
 
318
        return super(tender_line, self).write(cr, uid, ids, vals, context=context)
 
319
 
 
320
    def create(self, cr, uid, vals, context=None):
 
321
        if context is None:
 
322
            context = {}
 
323
        message = ''
 
324
        if not context.get('import_in_progress'):
 
325
            if vals.get('product_uom') and vals.get('product_id'):
 
326
                product_id = vals.get('product_id')
 
327
                product_uom = vals.get('product_uom')
 
328
                res = self.onchange_uom(cr, uid, False, product_id, product_uom, context=context)
 
329
                if res and res['warning']:
 
330
                    message += res['warning']['message']
 
331
            if message:
 
332
                raise osv.except_osv(_('Warning !'), _(message))
 
333
        return super(tender_line, self).create(cr, uid, vals, context=context)
 
334
 
 
335
tender_line()