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

« back to all changes in this revision

Viewing changes to msf_tools/msf_tools.py

  • Committer: Olivier DOSSMANN
  • Date: 2013-05-31 14:22:09 UTC
  • mto: This revision was merged to the branch mainline in revision 1687.
  • Revision ID: od@tempo-consulting.fr-20130531142209-sbcwvzuema11guzz
UF-1991 [FIX] Problem with wizard on "msg" field. Change it to "name".

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) 2011 TeMPO Consulting, MSF 
 
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, fields
 
23
 
 
24
import time
 
25
 
 
26
import inspect
 
27
 
 
28
from tools.translate import _
 
29
from dateutil.relativedelta import relativedelta
 
30
from datetime import datetime
 
31
 
 
32
import netsvc
 
33
 
 
34
class lang(osv.osv):
 
35
    '''
 
36
    define getter for date / time / datetime formats
 
37
    '''
 
38
    _inherit = 'res.lang'
 
39
    
 
40
    def _get_format(self, cr, uid, type, context=None):
 
41
        '''
 
42
        generic function
 
43
        '''
 
44
        if context is None:
 
45
            context = {}
 
46
        type = type + '_format'
 
47
        assert type in self._columns, 'Specified format field does not exist'
 
48
        user_obj = self.pool.get('res.users')
 
49
        # get user context lang
 
50
        user_lang = user_obj.read(cr, uid, uid, ['context_lang'], context=context)['context_lang']
 
51
        # get coresponding id
 
52
        lang_id = self.search(cr, uid, [('code','=',user_lang)])
 
53
        # return format value or from default function if not exists
 
54
        format = lang_id and self.read(cr, uid, lang_id[0], [type], context=context)[type] or getattr(self, '_get_default_%s'%type)(cr, uid, context=context)
 
55
        return format
 
56
    
 
57
    def _get_db_format(self, cr, uid, type, context=None):
 
58
        '''
 
59
        generic function - for now constant values
 
60
        '''
 
61
        if context is None:
 
62
            context = {}
 
63
        if type == 'date':
 
64
            return '%Y-%m-%d'
 
65
        if type == 'time':
 
66
            return '%H:%M:%S'
 
67
        # default value
 
68
        return '%Y-%m-%d'
 
69
lang()
 
70
 
 
71
 
 
72
class date_tools(osv.osv):
 
73
    '''
 
74
    date related tools for msf project
 
75
    '''
 
76
    _name = 'date.tools'
 
77
    
 
78
    def get_date_format(self, cr, uid, context=None):
 
79
        '''
 
80
        get the date format for the uid specified user
 
81
        
 
82
        from msf_order_date module
 
83
        '''
 
84
        lang_obj = self.pool.get('res.lang')
 
85
        return lang_obj._get_format(cr, uid, 'date', context=context)
 
86
    
 
87
    def get_db_date_format(self, cr, uid, context=None):
 
88
        '''
 
89
        return constant value
 
90
        '''
 
91
        lang_obj = self.pool.get('res.lang')
 
92
        return lang_obj._get_db_format(cr, uid, 'date', context=context)
 
93
    
 
94
    def get_time_format(self, cr, uid, context=None):
 
95
        '''
 
96
        get the time format for the uid specified user
 
97
        
 
98
        from msf_order_date module
 
99
        '''
 
100
        lang_obj = self.pool.get('res.lang')
 
101
        return lang_obj._get_format(cr, uid, 'time', context=context)
 
102
    
 
103
    def get_db_time_format(self, cr, uid, context=None):
 
104
        '''
 
105
        return constant value
 
106
        '''
 
107
        lang_obj = self.pool.get('res.lang')
 
108
        return lang_obj._get_db_format(cr, uid, 'time', context=context)
 
109
    
 
110
    def get_datetime_format(self, cr, uid, context=None):
 
111
        '''
 
112
        get the datetime format for the uid specified user
 
113
        '''
 
114
        return self.get_date_format(cr, uid, context=context) + ' ' + self.get_time_format(cr, uid, context=context)
 
115
    
 
116
    def get_db_datetime_format(self, cr, uid, context=None):
 
117
        '''
 
118
        return constant value
 
119
        '''
 
120
        return self.get_db_date_format(cr, uid, context=context) + ' ' + self.get_db_time_format(cr, uid, context=context)
 
121
    
 
122
    def get_date_formatted(self, cr, uid, d_type='date', datetime=None, context=None):
 
123
        '''
 
124
        Return the datetime in the format of the user
 
125
        @param d_type: 'date' or 'datetime' : determines which is the out format
 
126
        @param datetime: date to format 
 
127
        '''
 
128
        assert d_type in ('date', 'datetime'), 'Give only \'date\' or \'datetime\' as type parameter'
 
129
 
 
130
        if not datetime:
 
131
            datetime = time.strftime('%Y-%m-%d')
 
132
        
 
133
        if d_type == 'date':
 
134
            d_format = self.get_date_format(cr, uid)
 
135
            date = time.strptime(datetime, '%Y-%m-%d')
 
136
            return time.strftime(d_format, date)
 
137
        elif d_type == 'datetime':
 
138
            d_format = self.get_datetime_format(cr, uid)
 
139
            date = time.strptime(datetime, '%Y-%m-%d %H:%M:%S')
 
140
            return time.strftime(d_format, date)
 
141
    
 
142
date_tools()
 
143
 
 
144
 
 
145
class fields_tools(osv.osv):
 
146
    '''
 
147
    date related tools for msf project
 
148
    '''
 
149
    _name = 'fields.tools'
 
150
    
 
151
    def get_field_from_company(self, cr, uid, object=False, field=False, context=None):
 
152
        '''
 
153
        return the value for field from company for object 
 
154
        '''
 
155
        # field is required for value
 
156
        if not field:
 
157
            return False
 
158
        # object
 
159
        company_obj = self.pool.get('res.company')
 
160
        # corresponding company
 
161
        company_id = company_obj._company_default_get(cr, uid, object, context=context)
 
162
        # get the value
 
163
        res = company_obj.read(cr, uid, [company_id], [field], context=context)[0][field]
 
164
        return res
 
165
    
 
166
    def get_selection_name(self, cr, uid, object=False, field=False, key=False, context=None):
 
167
        '''
 
168
        return the name from the key of selection field
 
169
        '''
 
170
        if not object or not field or not key:
 
171
            return False
 
172
        # get the selection values list
 
173
        if isinstance(object, str):
 
174
            object = self.pool.get(object)
 
175
        list = object._columns[field].selection
 
176
        name = [x[1] for x in list if x[0] == key][0]
 
177
        return name
 
178
    
 
179
    def get_ids_from_browse_list(self, cr, uid, browse_list=False, context=None):
 
180
        '''
 
181
        return the list of ids corresponding to browse list in parameter
 
182
        '''
 
183
        if not browse_list:
 
184
            return []
 
185
        
 
186
        result = [x.id for x in browse_list]
 
187
        return result
 
188
    
 
189
fields_tools()
 
190
    
 
191
 
 
192
class data_tools(osv.osv):
 
193
    '''
 
194
    data related tools for msf project
 
195
    '''
 
196
    _name = 'data.tools'
 
197
    
 
198
    def load_common_data(self, cr, uid, ids, context=None):
 
199
        '''
 
200
        load common data into context
 
201
        '''
 
202
        if context is None:
 
203
            context = {}
 
204
        context.setdefault('common', {})
 
205
        # objects
 
206
        date_tools = self.pool.get('date.tools')
 
207
        obj_data = self.pool.get('ir.model.data')
 
208
        comp_obj = self.pool.get('res.company')
 
209
        # date format
 
210
        db_date_format = date_tools.get_db_date_format(cr, uid, context=context)
 
211
        context['common']['db_date_format'] = db_date_format
 
212
        date_format = date_tools.get_date_format(cr, uid, context=context)
 
213
        context['common']['date_format'] = date_format
 
214
        # date is today
 
215
        date = time.strftime(db_date_format)
 
216
        context['common']['date'] = date
 
217
        # default company id
 
218
        company_id = comp_obj._company_default_get(cr, uid, 'stock.picking', context=context)
 
219
        context['common']['company_id'] = company_id
 
220
        
 
221
        # stock location
 
222
        stock_id = obj_data.get_object_reference(cr, uid, 'stock', 'stock_location_stock')[1]
 
223
        context['common']['stock_id'] = stock_id
 
224
        # kitting location
 
225
        kitting_id = obj_data.get_object_reference(cr, uid, 'stock', 'location_production')[1]
 
226
        context['common']['kitting_id'] = kitting_id
 
227
        # input location
 
228
        input_id = obj_data.get_object_reference(cr, uid, 'msf_cross_docking', 'stock_location_input')[1]
 
229
        context['common']['input_id'] = input_id
 
230
        # quarantine analyze
 
231
        quarantine_anal = obj_data.get_object_reference(cr, uid, 'stock_override', 'stock_location_quarantine_analyze')[1]
 
232
        context['common']['quarantine_anal'] = quarantine_anal
 
233
        # quarantine before scrap
 
234
        quarantine_scrap = obj_data.get_object_reference(cr, uid, 'stock_override', 'stock_location_quarantine_scrap')[1]
 
235
        context['common']['quarantine_scrap'] = quarantine_scrap
 
236
        # log
 
237
        log = obj_data.get_object_reference(cr, uid, 'stock_override', 'stock_location_logistic')[1]
 
238
        context['common']['log'] = log
 
239
        # cross docking
 
240
        cross_docking = obj_data.get_object_reference(cr, uid, 'msf_cross_docking', 'stock_location_cross_docking')[1]
 
241
        context['common']['cross_docking'] = cross_docking
 
242
        
 
243
        # kit reason type
 
244
        reason_type_id = obj_data.get_object_reference(cr, uid, 'reason_types_moves', 'reason_type_kit')[1]
 
245
        context['common']['reason_type_id'] = reason_type_id
 
246
        # reason type goods return
 
247
        rt_goods_return = obj_data.get_object_reference(cr, uid, 'reason_types_moves', 'reason_type_goods_return')[1]
 
248
        context['common']['rt_goods_return'] = rt_goods_return
 
249
        # reason type goods replacement
 
250
        rt_goods_replacement = obj_data.get_object_reference(cr, uid, 'reason_types_moves', 'reason_type_goods_replacement')[1]
 
251
        context['common']['rt_goods_replacement'] = rt_goods_replacement
 
252
        # reason type internal supply
 
253
        rt_internal_supply = obj_data.get_object_reference(cr, uid, 'reason_types_moves', 'reason_type_internal_supply')[1]
 
254
        context['common']['rt_internal_supply'] = rt_internal_supply
 
255
        
 
256
        return True
 
257
 
 
258
data_tools()
 
259
 
 
260
 
 
261
class sequence_tools(osv.osv):
 
262
    '''
 
263
    sequence tools
 
264
    '''
 
265
    _name = 'sequence.tools'
 
266
    
 
267
    def reorder_sequence_number(self, cr, uid, base_object, base_seq_field, dest_object, foreign_field, foreign_ids, seq_field, context=None):
 
268
        '''
 
269
        receive a browse list corresponding to one2many lines
 
270
        recompute numbering corresponding to specified field
 
271
        compute next number of sequence
 
272
        
 
273
        we must make sure we reorder in conservative way according to original order
 
274
        
 
275
        *not used presently*
 
276
        '''
 
277
        # Some verifications
 
278
        if context is None:
 
279
            context = {}
 
280
        if isinstance(foreign_ids, (int, long)):
 
281
            foreign_ids = [foreign_ids]
 
282
            
 
283
        # objects
 
284
        base_obj = self.pool.get(base_object)
 
285
        dest_obj = self.pool.get(dest_object)
 
286
        seq_obj = self.pool.get('ir.sequence')
 
287
        
 
288
        for foreign_id in foreign_ids:
 
289
            # will be ordered by default according to db id, it's what we want according to user sequence
 
290
            item_ids = dest_obj.search(cr, uid, [(foreign_field, '=', foreign_id)], context=context)
 
291
            if item_ids:
 
292
                # read line number and id from items
 
293
                item_data = dest_obj.read(cr, uid, item_ids, [seq_field], context=context)
 
294
                # check the line number: data are ordered according to db id, so line number must be equal to index+1
 
295
                for i in range(len(item_data)):
 
296
                    if item_data[i][seq_field] != i+1:
 
297
                        dest_obj.write(cr, uid, [item_data[i]['id']], {seq_field: i+1}, context=context)
 
298
                # reset sequence to length + 1 all time, checking if needed would take much time
 
299
                # get the sequence id
 
300
                seq_id = base_obj.read(cr, uid, foreign_id, [base_seq_field], context=context)[base_seq_field][0]
 
301
                # we reset the sequence to length+1
 
302
                self.reset_next_number(cr, uid, [seq_id], value=len(item_ids)+1, context=context)
 
303
        
 
304
        return True
 
305
    
 
306
    def reorder_sequence_number_from_unlink(self, cr, uid, ids, base_object, base_seq_field, dest_object, foreign_field, seq_field, context=None):
 
307
        '''
 
308
        receive a browse list corresponding to one2many lines
 
309
        recompute numbering corresponding to specified field
 
310
        compute next number of sequence
 
311
        
 
312
        for unlink, only items with id > min(deleted id) are resequenced + reset the sequence value
 
313
        
 
314
        we must make sure we reorder in conservative way according to original order
 
315
        
 
316
        this method is called from methods of **destination object**
 
317
        '''
 
318
        # Some verifications
 
319
        if context is None:
 
320
            context = {}
 
321
        # if no ids as parameter return Tru
 
322
        if not ids:
 
323
            return True
 
324
            
 
325
        # objects
 
326
        base_obj = self.pool.get(base_object)
 
327
        dest_obj = self.pool.get(dest_object)
 
328
        seq_obj = self.pool.get('ir.sequence')
 
329
        
 
330
        # find the corresponding base ids
 
331
        base_ids = [x[foreign_field][0] for x in dest_obj.read(cr, uid, ids, [foreign_field], context=context) if x[foreign_field]]
 
332
        # simulate unique sql
 
333
        foreign_ids = set(base_ids)
 
334
        
 
335
        for foreign_id in foreign_ids:
 
336
            # will be ordered by default according to db id, it's what we want according to user sequence
 
337
            # reorder only ids bigger than min deleted + do not select deleted ones
 
338
            item_ids = dest_obj.search(cr, uid, [('id', '>', min(ids)), (foreign_field, '=', foreign_id), ('id', 'not in', ids)], context=context)
 
339
            # start numbering sequence
 
340
            start_num = 0
 
341
            # if deleted object is not the first one, we find the numbering value of previous one
 
342
            before_ids = dest_obj.search(cr, uid, [('id', '<', min(ids)), (foreign_field, '=', foreign_id)], context=context)
 
343
            if before_ids:
 
344
                # we read the numbering value of previous value (biggest id)
 
345
                start_num = dest_obj.read(cr, uid, max(before_ids), [seq_field], context=context)[seq_field]
 
346
            if item_ids:
 
347
                # read line number and id from items
 
348
                item_data = dest_obj.read(cr, uid, item_ids, [seq_field], context=context)
 
349
                # check the line number: data are ordered according to db id, so line number must be equal to index+1
 
350
                for i in range(len(item_data)):
 
351
                    # numbering value
 
352
                    start_num = start_num+1
 
353
                    if item_data[i][seq_field] != start_num:
 
354
                        dest_obj.write(cr, uid, [item_data[i]['id']], {seq_field: start_num}, context=context)
 
355
            
 
356
            # reset sequence to start_num + 1 all time, checking if needed would take much time
 
357
            # get the sequence id
 
358
            seq_id = base_obj.read(cr, uid, foreign_id, [base_seq_field], context=context)[base_seq_field][0]
 
359
            # we reset the sequence to length+1, whether or not items
 
360
            self.reset_next_number(cr, uid, [seq_id], value=start_num+1, context=context)
 
361
        
 
362
        return True
 
363
    
 
364
    def reset_next_number(self, cr, uid, seq_ids, value=1, context=None):
 
365
        '''
 
366
        reset the next number of the sequence to value, default value 1
 
367
        '''
 
368
        # Some verifications
 
369
        if context is None:
 
370
            context = {}
 
371
        if isinstance(seq_ids, (int, long)):
 
372
            seq_ids = [seq_ids]
 
373
            
 
374
        # objects
 
375
        seq_obj = self.pool.get('ir.sequence')
 
376
        seq_obj.write(cr, uid, seq_ids, {'number_next': value}, context=context)
 
377
        return True
 
378
    
 
379
    def create_sequence(self, cr, uid, vals, name, code, prefix='', padding=0, context=None):
 
380
        '''
 
381
        create a new sequence
 
382
        '''
 
383
        seq_pool = self.pool.get('ir.sequence')
 
384
        seq_typ_pool = self.pool.get('ir.sequence.type')
 
385
        
 
386
        assert name, 'create sequence: missing name'
 
387
        assert code, 'create sequence: missing code'
 
388
 
 
389
        types = {'name': name,
 
390
                 'code': code
 
391
                 }
 
392
        seq_typ_pool.create(cr, uid, types)
 
393
 
 
394
        seq = {'name': name,
 
395
               'code': code,
 
396
               'prefix': prefix,
 
397
               'padding': padding,
 
398
               }
 
399
        return seq_pool.create(cr, uid, seq)
 
400
    
 
401
sequence_tools()
 
402
 
 
403
 
 
404
class picking_tools(osv.osv):
 
405
    '''
 
406
    picking related tools
 
407
    '''
 
408
    _name = 'picking.tools'
 
409
    
 
410
    def confirm(self, cr, uid, ids, context=None):
 
411
        '''
 
412
        confirm the picking
 
413
        '''
 
414
        # Some verifications
 
415
        if context is None:
 
416
            context = {}
 
417
        if isinstance(ids, (int, long)):
 
418
            ids = [ids]
 
419
            
 
420
        # objects
 
421
        pick_obj = self.pool.get('stock.picking')
 
422
        pick_obj.draft_force_assign(cr, uid, ids, context)
 
423
        return True
 
424
        
 
425
    def check_assign(self, cr, uid, ids, context=None):
 
426
        '''
 
427
        check assign the picking
 
428
        '''
 
429
        # Some verifications
 
430
        if context is None:
 
431
            context = {}
 
432
        if isinstance(ids, (int, long)):
 
433
            ids = [ids]
 
434
            
 
435
        # objects
 
436
        pick_obj = self.pool.get('stock.picking')
 
437
        pick_obj.action_assign(cr, uid, ids, context)
 
438
        return True
 
439
    
 
440
    def force_assign(self, cr, uid, ids, context=None):
 
441
        '''
 
442
        force assign the picking
 
443
        '''
 
444
        # Some verifications
 
445
        if context is None:
 
446
            context = {}
 
447
        if isinstance(ids, (int, long)):
 
448
            ids = [ids]
 
449
            
 
450
        # objects
 
451
        pick_obj = self.pool.get('stock.picking')
 
452
        pick_obj.force_assign(cr, uid, ids, context)
 
453
        return True
 
454
        
 
455
    def validate(self, cr, uid, ids, context=None):
 
456
        '''
 
457
        validate the picking
 
458
        '''
 
459
        # Some verifications
 
460
        if context is None:
 
461
            context = {}
 
462
        if isinstance(ids, (int, long)):
 
463
            ids = [ids]
 
464
            
 
465
        # objects
 
466
        pick_obj = self.pool.get('stock.picking')
 
467
        wf_service = netsvc.LocalService("workflow")
 
468
        # trigger standard workflow for validated picking ticket
 
469
        for id in ids:
 
470
            pick_obj.action_move(cr, uid, [id])
 
471
            wf_service.trg_validate(uid, 'stock.picking', id, 'button_done', cr)
 
472
        return True
 
473
        
 
474
    def all(self, cr, uid, ids, context=None):
 
475
        '''
 
476
        confirm - check - validate
 
477
        '''
 
478
        self.confirm(cr, uid, ids, context=context)
 
479
        self.check_assign(cr, uid, ids, context=context)
 
480
        self.validate(cr, uid, ids, context=context)
 
481
        return True
 
482
    
 
483
picking_tools()
 
484
    
 
485
 
 
486
class ir_translation(osv.osv):
 
487
    _name = 'ir.translation'
 
488
    _inherit = 'ir.translation'
 
489
 
 
490
    def tr_view(self, cr, name, context):
 
491
        if not context or not context.get('lang'):
 
492
            return name
 
493
        tr = self._get_source(cr, 1, False, 'view', context['lang'], name, True)
 
494
        if not tr:
 
495
            # sometimes de view name is empty and so the action name is used as view name
 
496
            tr2 = self._get_source(cr, 1, 'ir.actions.act_window,name', 'model', context['lang'], name)
 
497
            if tr2:
 
498
                return tr2
 
499
            return name
 
500
        return tr
 
501
 
 
502
 
 
503
ir_translation()