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

« back to all changes in this revision

Viewing changes to mission_stock/mission_stock.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) 2011 MSF, TeMPO Consulting
 
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
 
 
25
from tools.translate import _
 
26
from spreadsheet_xml.spreadsheet_xml_write import SpreadsheetCreator
 
27
 
 
28
import pooler
 
29
import time
 
30
import threading
 
31
import base64
 
32
import logging
 
33
 
 
34
REPLACE_DICT = {'cell': 'Cell',
 
35
                'row': 'Row',
 
36
                'data': 'Data'}
 
37
 
 
38
def replace_all(text):
 
39
    for i, j in REPLACE_DICT.iteritems():
 
40
        text = text.replace(i, j)
 
41
    return text
 
42
 
 
43
 
 
44
class stock_mission_report(osv.osv):
 
45
    _name = 'stock.mission.report'
 
46
    _description = 'Mission stock report'
 
47
 
 
48
    def _get_local_report(self, cr, uid, ids, field_name, args, context=None):
 
49
        '''
 
50
        Check if the mission stock report is a local report or not
 
51
        '''
 
52
        if isinstance(ids, (int, long)):
 
53
            ids = [ids]
 
54
 
 
55
        res = {}
 
56
 
 
57
        local_instance_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.instance_id.id
 
58
 
 
59
        for report in self.read(cr, uid, ids, ['instance_id'], context=context):
 
60
            res[report['id']] = False
 
61
            if report['instance_id'] \
 
62
                and report['instance_id'][0] == local_instance_id:
 
63
                res[report['id']] = True
 
64
 
 
65
        return res
 
66
 
 
67
    def _src_local_report(self, cr, uid, obj, name, args, context=None):
 
68
        '''
 
69
        Returns the local or not report mission according to args
 
70
        '''
 
71
        res = []
 
72
 
 
73
        local_instance_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.instance_id.id
 
74
 
 
75
        for arg in args:
 
76
            if len(arg) > 2 and arg[0] == 'local_report':
 
77
                if (arg[1] == '=' and arg[2] in ('True', 'true', 't', 1)) or \
 
78
                    (arg[1] in ('!=', '<>') and arg[2] in ('False', 'false', 'f', 0)):
 
79
                    res.append(('instance_id', '=', local_instance_id))
 
80
                elif (arg[1] == '=' and arg[2] in ('False', 'false', 'f', 0)) or \
 
81
                    (arg[1] in ('!=', '<>') and arg[2] in ('True', 'true', 't', 1)):
 
82
                    res.append(('instance_id', '!=', local_instance_id))
 
83
                else:
 
84
                    raise osv.except_osv(_('Error'), _('Bad operator'))
 
85
 
 
86
        return res
 
87
 
 
88
    _columns = {
 
89
        'name': fields.char(size=128, string='Name', required=True),
 
90
        'instance_id': fields.many2one('msf.instance', string='Instance', required=True),
 
91
        'full_view': fields.boolean(string='Is a full view report ?'),
 
92
        'local_report': fields.function(_get_local_report, fnct_search=_src_local_report,
 
93
                                        type='boolean', method=True, store=False,
 
94
                                        string='Is a local report ?', help='If the report is a local report, it will be updated periodically'),
 
95
        'report_line': fields.one2many('stock.mission.report.line', 'mission_report_id', string='Lines'),
 
96
        'last_update': fields.datetime(string='Last update'),
 
97
        'move_ids': fields.many2many('stock.move', 'mission_move_rel', 'mission_id', 'move_id', string='Noves'),
 
98
        'export_ok': fields.boolean(string='Export file possible ?'),
 
99
        'ns_nv_file': fields.binary(string='XML export'),
 
100
        'ns_v_file': fields.binary(string='XML export'),
 
101
        's_nv_file': fields.binary(string='XML export'),
 
102
        's_v_file': fields.binary(string='XML export'),
 
103
    }
 
104
 
 
105
    _defaults = {
 
106
        'full_view': lambda *a: False,
 
107
        #'export_ok': False,
 
108
    }
 
109
 
 
110
    def create(self, cr, uid, vals, context=None):
 
111
        '''
 
112
        Create lines at report creation
 
113
        '''
 
114
        res = super(stock_mission_report, self).create(cr, uid, vals, context=context)
 
115
 
 
116
        local_instance_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.instance_id.id
 
117
 
 
118
        # Not update lines for full view or non local reports
 
119
        if vals.get('instance_id', False) and vals['instance_id'] == local_instance_id and not vals.get('full_view', False):
 
120
            if not context.get('no_update', False):
 
121
                self.update(cr, uid, res, context=context)
 
122
 
 
123
        return res
 
124
 
 
125
    def background_update(self, cr, uid, ids, context=None):
 
126
        """
 
127
        Run the update of local stock report in background
 
128
        """
 
129
        if not ids:
 
130
            ids = []
 
131
 
 
132
        threaded_calculation = threading.Thread(target=self.update_newthread, args=(cr, uid, ids, context))
 
133
        threaded_calculation.start()
 
134
        return {'type': 'ir.actions.act_window_close'}
 
135
 
 
136
    def update_newthread(self, cr, uid, ids=[], context=None):
 
137
        # Open a new cursor : Don't forget to close it at the end of method
 
138
        cr = pooler.get_db(cr.dbname).cursor()
 
139
        a = time.strftime('%H-%M-%S')
 
140
        try:
 
141
            self.update(cr, uid, ids=[], context=None)
 
142
            cr.commit()
 
143
        finally:
 
144
            cr.close()
 
145
 
 
146
    def update(self, cr, uid, ids=[], context=None):
 
147
        '''
 
148
        Create lines if new products exist or update the existing lines
 
149
        '''
 
150
        if not context:
 
151
            context = {}
 
152
 
 
153
        if isinstance(ids, (int, long)):
 
154
            ids = [ids]
 
155
 
 
156
        line_obj = self.pool.get('stock.mission.report.line')
 
157
 
 
158
        report_ids = self.search(cr, uid, [('local_report', '=', True)], context=context)
 
159
        full_report_ids = self.search(cr, uid, [('full_view', '=', True)], context=context)
 
160
        instance_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.instance_id
 
161
        line_ids = []
 
162
 
 
163
        # Create a local report if no exist
 
164
        if not report_ids and context.get('update_mode', False) not in ('update', 'init') and instance_id:
 
165
            c = context.copy()
 
166
            c.update({'no_update': True})
 
167
            report_ids = [self.create(cr, uid, {'name': instance_id.name,
 
168
                                               'instance_id': instance_id.id,
 
169
                                               'full_view': False}, context=c)]
 
170
 
 
171
        # Create a full view report if no exist
 
172
        if not full_report_ids and context.get('update_mode', False) not in ('update', 'init') and instance_id:
 
173
            c = context.copy()
 
174
            c.update({'no_update': True})
 
175
            full_report_ids = [self.create(cr, uid, {'name': 'Full view',
 
176
                                               'instance_id': instance_id.id,
 
177
                                               'full_view': True}, context=c)]
 
178
 
 
179
        cr.commit()
 
180
 
 
181
        if context.get('update_full_report'):
 
182
            report_ids = full_report_ids
 
183
 
 
184
        product_ids = self.pool.get('product.product').search(cr, uid, [], context=context)
 
185
        product_values = {}
 
186
        for product in self.pool.get('product.product').read(cr, uid, product_ids, ['product_amc', 'reviewed_consumption'], context=context):
 
187
            product_values.setdefault(product['id'], {})
 
188
            product_values[product['id']].setdefault('product_amc', product['product_amc'])
 
189
            product_values[product['id']].setdefault('reviewed_consumption', product['reviewed_consumption'])
 
190
 
 
191
 
 
192
        # Check in each report if new products are in the database and not in the report
 
193
        for report in self.read(cr, uid, report_ids, ['local_report', 'full_view'], context=context):
 
194
            #self.write(cr, uid, [report.id], {'export_ok': False}, context=context)
 
195
            # Create one line by product
 
196
            cr.execute('''SELECT id FROM product_product
 
197
                        EXCEPT
 
198
                          SELECT product_id FROM stock_mission_report_line WHERE mission_report_id = %s''' % report['id'])
 
199
            for product in cr.fetchall():
 
200
                line_ids.append(line_obj.create(cr, uid, {'product_id': product, 'mission_report_id': report['id']}, context=context))
 
201
 
 
202
            # Don't update lines for full view or non local reports
 
203
            if not report['local_report']:
 
204
                continue
 
205
 
 
206
            # Update the update date on report
 
207
            self.write(cr, uid, [report['id']], {'last_update': time.strftime('%Y-%m-%d %H:%M:%S'),
 
208
                                              'export_ok': False}, context=context)
 
209
 
 
210
            if context.get('update_full_report'):
 
211
                full_view = self.search(cr, uid, [('full_view', '=', True)])
 
212
                if full_view:
 
213
                    line_ids = line_obj.search(cr, uid, [('mission_report_id', 'in', full_view)])
 
214
                    line_obj.update_full_view_line(cr, uid, line_ids, context=context)
 
215
            elif not report['full_view']:
 
216
                # Update all lines
 
217
                self.update_lines(cr, uid, [report['id']])
 
218
 
 
219
            self._get_export_csv(cr, uid, report['id'], product_values, context=context)
 
220
 
 
221
        # After update of all normal reports, update the full view report
 
222
        if not context.get('update_full_report'):
 
223
            c = context.copy()
 
224
            c.update({'update_full_report': True})
 
225
            self.update(cr, uid, [], context=c)
 
226
 
 
227
        return True
 
228
 
 
229
    def update_lines(self, cr, uid, ids, context=None):
 
230
        location_obj = self.pool.get('stock.location')
 
231
        data_obj = self.pool.get('ir.model.data')
 
232
        line_obj = self.pool.get('stock.mission.report.line')
 
233
        product_obj = self.pool.get('product.product')
 
234
        # Search considered SLocation
 
235
        stock_location_id = data_obj.get_object_reference(cr, uid, 'stock', 'stock_location_stock')
 
236
        if stock_location_id:
 
237
            stock_location_id = stock_location_id[1]
 
238
        internal_loc = location_obj.search(cr, uid, [('usage', '=', 'internal')], context=context)
 
239
        central_loc = location_obj.search(cr, uid, [('central_location_ok', '=', True)], context=context)
 
240
        cross_loc = location_obj.search(cr, uid, [('cross_docking_location_ok', '=', True)], context=context)
 
241
        stock_loc = location_obj.search(cr, uid, [('location_id', 'child_of', stock_location_id),
 
242
                                                  ('id', 'not in', cross_loc),
 
243
                                                  ('central_location_ok', '=', False)], context=context)
 
244
        cu_loc = location_obj.search(cr, uid, [('usage', '=', 'internal'), ('location_category', '=', 'consumption_unit')], context=context)
 
245
        secondary_location_id = data_obj.get_object_reference(cr, uid, 'msf_config_locations', 'stock_location_intermediate_client_view')
 
246
        if secondary_location_id:
 
247
            secondary_location_id = secondary_location_id[1]
 
248
        secondary_location_ids = location_obj.search(cr, uid, [('location_id', 'child_of', secondary_location_id)], context=context)
 
249
 
 
250
        cu_loc = location_obj.search(cr, uid, [('location_id', 'child_of', cu_loc)], context=context)
 
251
        central_loc = location_obj.search(cr, uid, [('location_id', 'child_of', central_loc)], context=context)
 
252
 
 
253
        # Check if the instance is a coordination or a project
 
254
        coordo_id = False
 
255
        company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
 
256
        coordo = self.pool.get('msf.instance').search(cr, uid, [('level', '=', 'coordo')], context=context)
 
257
        if company.instance_id.level == 'project' and coordo:
 
258
            coordo_id = self.pool.get('msf.instance').browse(cr, uid, coordo[0], context=context).instance
 
259
 
 
260
        for id in ids:
 
261
            # In-Pipe moves
 
262
            cr.execute('''SELECT m.product_id, m.product_qty, m.product_uom, p.name, m.id
 
263
                          FROM stock_move m
 
264
                              LEFT JOIN stock_picking s ON m.picking_id = s.id
 
265
                              LEFT JOIN res_partner p ON s.partner_id2 = p.id
 
266
                          WHERE s.type = 'in' AND m.state in ('confirmed', 'waiting', 'assigned')''')
 
267
 
 
268
            in_pipe_moves = cr.fetchall()
 
269
            for product_id, qty, uom, partner, move_id in in_pipe_moves:
 
270
                line_id = line_obj.search(cr, uid, [('product_id', '=', product_id),
 
271
                                                    ('mission_report_id', '=', id)])
 
272
                if line_id:
 
273
                    line = line_obj.browse(cr, uid, line_id[0])
 
274
                    if uom != line.product_id.uom_id.id:
 
275
                        qty = self.pool.get('product.uom')._compute_qty(cr, uid, uom, qty, line.product_id.uom_id.id)
 
276
 
 
277
                    vals = {'in_pipe_qty': 0.00,
 
278
                            'in_pipe_coor_qty': 0.00,
 
279
                            'updated': True}
 
280
 
 
281
                    vals['in_pipe_qty'] = vals['in_pipe_qty'] + qty
 
282
 
 
283
                    if partner == coordo_id:
 
284
                        vals['in_pipe_coor_qty'] = vals['in_pipe_coor_qty'] + qty
 
285
 
 
286
                    line_obj.write(cr, uid, line.id, vals)
 
287
 
 
288
            # All other moves
 
289
            cr.execute('''
 
290
                        SELECT id, product_id, product_uom, product_qty, location_id, location_dest_id
 
291
                        FROM stock_move
 
292
                        WHERE state = 'done'
 
293
                        AND id not in (SELECT move_id FROM mission_move_rel WHERE mission_id = %s)
 
294
            ''' % (id))
 
295
            res = cr.fetchall()
 
296
            for move in res:
 
297
                cr.execute('INSERT INTO mission_move_rel VALUES (%s, %s)' % (id, move[0]))
 
298
                product = product_obj.browse(cr, uid, move[1])
 
299
                line_id = line_obj.search(cr, uid, [('product_id', '=', move[1]),
 
300
                                                    ('mission_report_id', '=', id)])
 
301
                if line_id:
 
302
                    line = line_obj.browse(cr, uid, line_id[0])
 
303
                    qty = self.pool.get('product.uom')._compute_qty(cr, uid, move[2], move[3], product.uom_id.id)
 
304
                    vals = {'internal_qty': line.internal_qty or 0.00,
 
305
                            'stock_qty': line.stock_qty or 0.00,
 
306
                            'central_qty': line.central_qty or 0.00,
 
307
                            'cross_qty': line.cross_qty or 0.00,
 
308
                            'secondary_qty': line.secondary_qty or 0.00,
 
309
                            'cu_qty': line.cu_qty or 0.00,
 
310
                            'updated': True}
 
311
 
 
312
                    if move[4] in internal_loc:
 
313
                        vals['internal_qty'] = vals['internal_qty'] - qty
 
314
                    if move[4] in stock_loc:
 
315
                        vals['stock_qty'] = vals['stock_qty'] - qty
 
316
                    if move[4] in central_loc:
 
317
                        vals['central_qty'] = vals['central_qty'] - qty
 
318
                    if move[4] in cross_loc:
 
319
                        vals['cross_qty'] = vals['cross_qty'] - qty
 
320
                    if move[4] in secondary_location_ids:
 
321
                        vals['secondary_qty'] = vals['secondary_qty'] - qty
 
322
                    if move[4] in cu_loc:
 
323
                        vals['cu_qty'] = vals['cu_qty'] - qty
 
324
 
 
325
                    if move[5] in internal_loc:
 
326
                        vals['internal_qty'] = vals['internal_qty'] + qty
 
327
                    if move[5] in stock_loc:
 
328
                        vals['stock_qty'] = vals['stock_qty'] + qty
 
329
                    if move[5] in central_loc:
 
330
                        vals['central_qty'] = vals['central_qty'] + qty
 
331
                    if move[5] in cross_loc:
 
332
                        vals['cross_qty'] = vals['cross_qty'] + qty
 
333
                    if move[5] in secondary_location_ids:
 
334
                        vals['secondary_qty'] = vals['secondary_qty'] + qty
 
335
                    if move[5] in cu_loc:
 
336
                        vals['cu_qty'] = vals['cu_qty'] + qty
 
337
 
 
338
                    vals.update({'internal_val': vals['internal_qty'] * product.standard_price})
 
339
                    line_obj.write(cr, uid, line.id, vals)
 
340
 
 
341
        return True
 
342
 
 
343
    def _get_export_csv(self, cr, uid, ids, product_values, context=None):
 
344
        '''
 
345
        Get the XML files of the stock mission report.
 
346
        This method generates 4 files (according to option set) :
 
347
            * 1 file with no split of WH and no valuation
 
348
            * 1 file with no split of WH and valuation
 
349
            * 1 file with split of WH and valuation
 
350
            * 1 file with split aof WH and valuation
 
351
        '''
 
352
        context = context or {}
 
353
        if isinstance(ids, (int, long)):
 
354
            ids = [ids]
 
355
 
 
356
        line_obj = self.pool.get('stock.mission.report.line')
 
357
 
 
358
        # ns_nv => No split, no valuation
 
359
        # ns_v => No split, valuation
 
360
        # s_nv => Split, no valuation
 
361
        # s_v => Split, valuation
 
362
        # headers (_(Field name), Field type, Technical field name, ns_nv, ns_v, s_nv, s_v
 
363
        headers = [(_('Reference'), 'string', 'default_code', 1, 1, 1, 1),
 
364
                   (_('Name'), 'string', 'name', 1, 1, 1, 1),
 
365
                   (_('UoM'), 'string', 'uom_id', 1, 1, 1, 1),
 
366
                   (_('Cost price'), 'number', 'cost_price', 0, 1, 0, 1),
 
367
                   (_('Func. Cur.'), 'string', 'currency_id', 0, 1, 0, 1),
 
368
                   (_('Instance stock'), 'number', 'internal_qty', 1, 1, 1, 1),
 
369
                   (_('Instance stock val.'), 'number', 'internal_val', 0, 1, 0, 1),
 
370
                   (_('Warehouse stock'), 'number', 'wh_qty', 1, 1, 0, 0),
 
371
                   (_('Stock Qty.'), 'number', 'stock_qty', 0, 0, 1, 1),
 
372
                   (_('Unallocated Stock Qty.'), 'number', 'central_qty', 0, 0, 1, 1),
 
373
                   (_('Cross-Docking Qty.'), 'number', 'cross_qty', 1, 1, 1, 1),
 
374
                   (_('Secondary Stock Qty.'), 'number', 'secondary_qty', 1, 1, 1, 1),
 
375
                   (_('Internal Cons. Unit Qty.'), 'number', 'cu_qty', 1, 1, 1, 1),
 
376
                   (_('AMC'), 'number', 'product_amc', 1, 1, 1, 1),
 
377
                   (_('FMC'), 'number', 'reviewed_consumption', 1, 1, 1, 1),
 
378
                   (_('In Pipe Qty.'), 'number', 'in_pipe_qty', 1, 1, 1, 1),]
 
379
        fields = ['product_amc', 'reviewed_consumption']
 
380
 
 
381
        def set_data(request, report_id, line, data_name,):
 
382
            data = ''
 
383
            cr.execute(request, (report_id, line['id']))
 
384
            try:
 
385
                product_amc = line['product_id'][0] in product_values and product_values[line['product_id'][0]]['product_amc'] or 0.00
 
386
                reviewed_consumption = line['product_id'][0] in product_values and product_values[line['product_id'][0]]['reviewed_consumption'] or 0.00
 
387
                for r in cr.dictfetchall():
 
388
                    data += r[data_name] % (product_amc, reviewed_consumption)
 
389
            except Exception, e:
 
390
                logging.getLogger('Mission stock report').warning("""An error is occured when compute the consumption values for product at mission stock report file generation. Data: \n %s""" % data_name)
 
391
 
 
392
            data += '\n'
 
393
            return data
 
394
 
 
395
#        for report in self.browse(cr, uid, ids, context=context):
 
396
        for report_id in ids:
 
397
            # No split, no valuation
 
398
            ns_nv_headers = [(x[0], x[1]) for x in headers if x[3] == 1]
 
399
            ns_nv_data = ''
 
400
            # No split, valuation
 
401
            ns_v_headers = [(x[0], x[1]) for x in headers if x[4] == 1]
 
402
            ns_v_data = ''
 
403
            # Split, no valuation
 
404
            s_nv_headers = [(x[0], x[1]) for x in headers if x[5] == 1]
 
405
            s_nv_data = ''
 
406
            # Split, valuation
 
407
            s_v_headers = [(x[0], x[1]) for x in headers if x[6] == 1]
 
408
            s_v_data = ''
 
409
 
 
410
#            lines_ids = line_obj.search(cr, uid, [('mission_report_id', '=', report_id)], context=context)
 
411
#            start = 0
 
412
 
 
413
#            for line in line_obj.read(cr, uid, lines_ids, ['product_id'], context=context):
 
414
                # No split, No valuation
 
415
            request = '''SELECT
 
416
                l.product_id AS product_id,
 
417
                xmlelement(name Row,
 
418
 
 
419
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
420
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
421
                replace(l.default_code, '%%', '%%%%'))),
 
422
 
 
423
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
424
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
425
                replace(pt.name, '%%', '%%%%'))),
 
426
 
 
427
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
428
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
429
                replace(pu.name, '%%', '%%%%'))),
 
430
 
 
431
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
432
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
433
                trim(to_char(l.internal_qty, '999999999999.999')))),
 
434
 
 
435
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
436
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
437
                trim(to_char(l.wh_qty, '999999999999.999')))),
 
438
 
 
439
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
440
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
441
                trim(to_char(l.cross_qty, '999999999999.999')))),
 
442
 
 
443
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
444
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
445
                trim(to_char(l.secondary_qty, '999999999999.999')))),
 
446
 
 
447
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
448
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
449
                trim(to_char(l.cu_qty, '999999999999.999')))),
 
450
 
 
451
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
452
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
453
                '%%s')),
 
454
 
 
455
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
456
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
457
                '%%s')),
 
458
 
 
459
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
460
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
461
                trim(to_char(l.in_pipe_qty, '999999999999.999'))))
 
462
                ) AS ns_nv_data,
 
463
                xmlelement(name Row,
 
464
 
 
465
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
466
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
467
                replace(l.default_code, '%%', '%%%%'))),
 
468
 
 
469
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
470
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
471
                replace(pt.name, '%%', '%%%%'))),
 
472
 
 
473
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
474
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
475
                replace(pu.name, '%%', '%%%%'))),
 
476
 
 
477
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
478
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
479
                trim(to_char(l.internal_qty, '999999999999.999')))),
 
480
 
 
481
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
482
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
483
                trim(to_char(l.stock_qty, '999999999999.999')))),
 
484
 
 
485
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
486
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
487
                trim(to_char(l.central_qty, '999999999999.999')))),
 
488
 
 
489
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
490
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
491
                trim(to_char(l.cross_qty, '999999999999.999')))),
 
492
 
 
493
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
494
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
495
                trim(to_char(l.secondary_qty, '999999999999.999')))),
 
496
 
 
497
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
498
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
499
                trim(to_char(l.cu_qty, '999999999999.999')))),
 
500
 
 
501
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
502
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
503
                '%%s')),
 
504
 
 
505
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
506
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
507
                '%%s')),
 
508
 
 
509
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
510
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
511
                trim(to_char(l.in_pipe_qty, '999999999999.999'))))
 
512
                ) AS s_nv_data,
 
513
                xmlelement(name Row,
 
514
 
 
515
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
516
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
517
                replace(l.default_code, '%%', '%%%%'))),
 
518
 
 
519
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
520
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
521
                replace(pt.name, '%%', '%%%%'))),
 
522
 
 
523
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
524
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
525
                replace(pu.name, '%%', '%%%%'))),
 
526
 
 
527
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
528
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
529
                trim(to_char(pt.standard_price, '999999999999.999')))),
 
530
 
 
531
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
532
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
533
                rc.name)),
 
534
 
 
535
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
536
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
537
                trim(to_char(l.internal_qty, '999999999999.999')))),
 
538
 
 
539
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
540
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
541
                trim(to_char((l.internal_qty * pt.standard_price), '999999999999.999')))),
 
542
 
 
543
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
544
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
545
                trim(to_char(l.wh_qty, '999999999999.999')))),
 
546
 
 
547
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
548
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
549
                trim(to_char(l.cross_qty, '999999999999.999')))),
 
550
 
 
551
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
552
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
553
                trim(to_char(l.secondary_qty, '999999999999.999')))),
 
554
 
 
555
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
556
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
557
                trim(to_char(l.cu_qty, '999999999999.999')))),
 
558
 
 
559
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
560
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
561
                '%%s')),
 
562
 
 
563
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
564
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
565
                '%%s')),
 
566
 
 
567
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
568
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
569
                trim(to_char(l.in_pipe_qty, '999999999999.999'))))
 
570
                ) AS ns_v_data,
 
571
                xmlelement(name Row,
 
572
 
 
573
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
574
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
575
                replace(l.default_code, '%%', '%%%%'))),
 
576
 
 
577
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
578
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
579
                replace(pt.name, '%%', '%%%%'))),
 
580
 
 
581
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
582
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
583
                replace(pu.name, '%%', '%%%%'))),
 
584
 
 
585
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
586
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
587
                trim(to_char((l.internal_qty * pt.standard_price), '999999999999.999')))),
 
588
 
 
589
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
590
                xmlelement(name Data, xmlattributes('String' as "ss:Type"),
 
591
                rc.name)),
 
592
 
 
593
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
594
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
595
                trim(to_char(l.internal_qty, '999999999999.999')))),
 
596
 
 
597
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
598
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
599
                trim(to_char((l.internal_qty * pt.standard_price), '999999999999.999')))),
 
600
 
 
601
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
602
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
603
                trim(to_char(l.stock_qty, '999999999999.999')))),
 
604
 
 
605
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
606
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
607
                trim(to_char(l.central_qty, '999999999999.999')))),
 
608
 
 
609
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
610
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
611
                trim(to_char(l.cross_qty, '999999999999.999')))),
 
612
 
 
613
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
614
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
615
                trim(to_char(l.secondary_qty, '999999999999.999')))),
 
616
 
 
617
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
618
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
619
                trim(to_char(l.cu_qty, '999999999999.999')))),
 
620
 
 
621
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
622
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
623
                '%%s')),
 
624
 
 
625
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
626
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
627
                '%%s')),
 
628
 
 
629
                xmlelement(name Cell, xmlattributes('ssBorder' as "ss:StyleID"),
 
630
                xmlelement(name Data, xmlattributes('Number' as "ss:Type"),
 
631
                trim(to_char(l.in_pipe_qty, '999999999999.999'))))
 
632
                ) AS s_v_data
 
633
            FROM stock_mission_report_line l
 
634
                 LEFT JOIN product_product pp ON l.product_id = pp.id
 
635
                 LEFT JOIN product_template pt ON pp.product_tmpl_id = pt.id
 
636
                 LEFT JOIN product_uom pu ON pt.uom_id = pu.id
 
637
                 LEFT JOIN res_currency rc ON pp.currency_id = rc.id
 
638
            WHERE l.mission_report_id = %s'''
 
639
 
 
640
            cr.execute(request, (report_id, ))
 
641
            res = cr.dictfetchall()
 
642
            for line in res:
 
643
                try:
 
644
                    product_amc = line['product_id'] in product_values and product_values[line['product_id']]['product_amc'] or 0.00
 
645
                    reviewed_consumption = line['product_id'] in product_values and product_values[line['product_id']]['reviewed_consumption'] or 0.00
 
646
                    ns_nv_data += replace_all(line['ns_nv_data'] % (product_amc, reviewed_consumption))
 
647
                    ns_v_data  += replace_all(line['ns_v_data'] % (product_amc, reviewed_consumption))
 
648
                    s_nv_data  += replace_all(line['s_nv_data'] % (product_amc, reviewed_consumption))
 
649
                    s_v_data   += replace_all(line['s_v_data'] % (product_amc, reviewed_consumption))
 
650
                except Exception, e:
 
651
                    logging.getLogger('Mission stock report').warning("""An error is occured when generate the mission stock report file. Data: \n %s""" % line)
 
652
 
 
653
            # No split - No valuation
 
654
            ns_nv_tmpl = SpreadsheetCreator('Template of Mission stock - No split - No valuation', ns_nv_headers, [])
 
655
            ns_nv_split = ns_nv_tmpl.get_xml(default_filters=['decode.utf8']).split('</Row>')
 
656
            ns_nv_split[0] = ns_nv_split[0].replace('ss:ExpandedRowCount="1" ', '')
 
657
            ns_nv_file = base64.encodestring(ns_nv_split[0] + '</Row>' + ns_nv_data + ns_nv_split[1])
 
658
            del ns_nv_tmpl
 
659
            del ns_nv_split
 
660
            del ns_nv_data
 
661
 
 
662
 
 
663
            # No split, valuation
 
664
            ns_v_tmpl = SpreadsheetCreator('Template of Mission stock - No split - No valuation', ns_v_headers, [])
 
665
            ns_v_split = ns_v_tmpl.get_xml(default_filters=['decode.utf8']).split('</Row>')
 
666
            ns_v_split[0] = ns_v_split[0].replace('ss:ExpandedRowCount="1" ', '')
 
667
            ns_v_file = base64.encodestring(ns_v_split[0] + '</Row>' + ns_v_data + ns_v_split[1])
 
668
            del ns_v_tmpl
 
669
            del ns_v_split
 
670
            del ns_v_data
 
671
 
 
672
 
 
673
            # Split, no valuation
 
674
            s_nv_tmpl = SpreadsheetCreator('Template of Mission stock - No split - No valuation', s_nv_headers, [])
 
675
            s_nv_split = s_nv_tmpl.get_xml(default_filters=['decode.utf8']).split('</Row>')
 
676
            s_nv_split[0] = s_nv_split[0].replace('ss:ExpandedRowCount="1" ', '')
 
677
            s_nv_file = base64.encodestring(s_nv_split[0] + '</Row>' + s_nv_data + s_nv_split[1])
 
678
            del s_nv_tmpl
 
679
            del s_nv_split
 
680
            del s_nv_data
 
681
 
 
682
 
 
683
            # Split, valuation
 
684
            s_v_tmpl = SpreadsheetCreator('Template of Mission stock - No split - No valuation', s_v_headers, [])
 
685
            s_v_split = s_v_tmpl.get_xml(default_filters=['decode.utf8']).split('</Row>')
 
686
            s_v_split[0] = s_v_split[0].replace('ss:ExpandedRowCount="1" ', '')
 
687
            s_v_file = base64.encodestring(s_v_split[0] + '</Row>' + s_v_data + s_v_split[1])
 
688
            del s_v_tmpl
 
689
            del s_v_split
 
690
            del s_v_data
 
691
 
 
692
 
 
693
            self.write(cr, uid, [report_id], {'ns_nv_file': ns_nv_file,
 
694
                                              'ns_v_file': ns_v_file,
 
695
                                              's_nv_file': s_nv_file,
 
696
                                              's_v_file': s_v_file,
 
697
                                              'export_ok': True}, context=context)
 
698
 
 
699
        return True
 
700
 
 
701
stock_mission_report()
 
702
 
 
703
 
 
704
class stock_mission_report_line(osv.osv):
 
705
    _name = 'stock.mission.report.line'
 
706
    _description = 'Mission stock report line'
 
707
    _order = 'default_code'
 
708
 
 
709
    def _get_product_type_selection(self, cr, uid, context=None):
 
710
        return self.pool.get('product.template').PRODUCT_TYPE
 
711
 
 
712
    def _get_product_subtype_selection(self, cr, uid, context=None):
 
713
        return self.pool.get('product.template').PRODUCT_SUBTYPE
 
714
 
 
715
    def onChangeSearchNomenclature(self, cr, uid, id, position, type, nomen_manda_0, nomen_manda_1, nomen_manda_2, nomen_manda_3, num=True, context=None):
 
716
        return self.pool.get('product.product').onChangeSearchNomenclature(cr, uid, id, position, type, nomen_manda_0, nomen_manda_1, nomen_manda_2, nomen_manda_3, num=num, context=context)
 
717
 
 
718
    def _get_nomen_s(self, cr, uid, ids, fields, *a, **b):
 
719
        value = {}
 
720
        for f in fields:
 
721
            value[f] = False
 
722
 
 
723
        ret = {}
 
724
        for id in ids:
 
725
            ret[id] = value
 
726
        return ret
 
727
 
 
728
    def _search_nomen_s(self, cr, uid, obj, name, args, context=None):
 
729
        # Some verifications
 
730
        if context is None:
 
731
            context = {}
 
732
 
 
733
        if not args:
 
734
            return []
 
735
        narg = []
 
736
        for arg in args:
 
737
            el = arg[0].split('_')
 
738
            el.pop()
 
739
            narg = [('_'.join(el), arg[1], arg[2])]
 
740
 
 
741
        return narg
 
742
 
 
743
    def _get_template(self, cr, uid, ids, context=None):
 
744
        return self.pool.get('stock.mission.report.line').search(cr, uid, [('product_id.product_tmpl_id', 'in', ids)], context=context)
 
745
 
 
746
    def _get_wh_qty(self, cr, uid, ids, field_name, args, context=None):
 
747
        res = {}
 
748
        for line in self.browse(cr, uid, ids, context=context):
 
749
            res[line.id] = line.stock_qty + line.central_qty
 
750
 
 
751
        return res
 
752
 
 
753
    def _get_internal_val(self, cr, uid, ids, field_name, args, context=None):
 
754
        res = {}
 
755
        for line in self.browse(cr, uid, ids, context=context):
 
756
            res[line.id] = line.internal_qty * line.cost_price
 
757
 
 
758
        return res
 
759
 
 
760
    _columns = {
 
761
        'product_id': fields.many2one('product.product', string='Name', required=True, ondelete="cascade"),
 
762
        'default_code': fields.related('product_id', 'default_code', string='Reference', type='char', size=64, store=True),
 
763
        'old_code': fields.related('product_id', 'old_code', string='Old Code', type='char'),
 
764
        'name': fields.related('product_id', 'name', string='Name', type='char'),
 
765
        'categ_id': fields.related('product_id', 'categ_id', string='Category', type='many2one', relation='product.category',
 
766
                                   store={'product.template': (_get_template, ['type'], 10),
 
767
                                          'stock.mission.report.line': (lambda self, cr, uid, ids, c={}: ids, ['product_id'], 10)}),
 
768
        'type': fields.related('product_id', 'type', string='Type', type='selection', selection=_get_product_type_selection,
 
769
                               store={'product.template': (_get_template, ['type'], 10),
 
770
                                      'stock.mission.report.line': (lambda self, cr, uid, ids, c={}: ids, ['product_id'], 10)}),
 
771
        'subtype': fields.related('product_id', 'subtype', string='Subtype', type='selection', selection=_get_product_subtype_selection,
 
772
                                  store={'product.template': (_get_template, ['subtype'], 10),
 
773
                                         'stock.mission.report.line': (lambda self, cr, uid, ids, c={}: ids, ['product_id'], 10)}),
 
774
        # mandatory nomenclature levels
 
775
        'nomen_manda_0': fields.related('product_id', 'nomen_manda_0', type='many2one', relation='product.nomenclature', string='Main Type'),
 
776
        'nomen_manda_1': fields.related('product_id', 'nomen_manda_1', type='many2one', relation='product.nomenclature', string='Group'),
 
777
        'nomen_manda_2': fields.related('product_id', 'nomen_manda_2', type='many2one', relation='product.nomenclature', string='Family'),
 
778
        'nomen_manda_3': fields.related('product_id', 'nomen_manda_3', type='many2one', relation='product.nomenclature', string='Root'),
 
779
        # optional nomenclature levels
 
780
        'nomen_sub_0': fields.related('product_id', 'nomen_sub_0', type='many2one', relation='product.nomenclature', string='Sub Class 1'),
 
781
        'nomen_sub_1': fields.related('product_id', 'nomen_sub_1', type='many2one', relation='product.nomenclature', string='Sub Class 2'),
 
782
        'nomen_sub_2': fields.related('product_id', 'nomen_sub_2', type='many2one', relation='product.nomenclature', string='Sub Class 3'),
 
783
        'nomen_sub_3': fields.related('product_id', 'nomen_sub_3', type='many2one', relation='product.nomenclature', string='Sub Class 4'),
 
784
        'nomen_sub_4': fields.related('product_id', 'nomen_sub_4', type='many2one', relation='product.nomenclature', string='Sub Class 5'),
 
785
        'nomen_sub_5': fields.related('product_id', 'nomen_sub_5', type='many2one', relation='product.nomenclature', string='Sub Class 6'),
 
786
        'nomen_manda_0_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Main Type', fnct_search=_search_nomen_s, multi="nom_s"),
 
787
        'nomen_manda_1_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Group', fnct_search=_search_nomen_s, multi="nom_s"),
 
788
        'nomen_manda_2_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Family', fnct_search=_search_nomen_s, multi="nom_s"),
 
789
        'nomen_manda_3_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Root', fnct_search=_search_nomen_s, multi="nom_s"),
 
790
        'nomen_sub_0_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Sub Class 1', fnct_search=_search_nomen_s, multi="nom_s"),
 
791
        'nomen_sub_1_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Sub Class 2', fnct_search=_search_nomen_s, multi="nom_s"),
 
792
        'nomen_sub_2_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Sub Class 3', fnct_search=_search_nomen_s, multi="nom_s"),
 
793
        'nomen_sub_3_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Sub Class 4', fnct_search=_search_nomen_s, multi="nom_s"),
 
794
        'nomen_sub_4_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Sub Class 5', fnct_search=_search_nomen_s, multi="nom_s"),
 
795
        'nomen_sub_5_s': fields.function(_get_nomen_s, method=True, type='many2one', relation='product.nomenclature', string='Sub Class 6', fnct_search=_search_nomen_s, multi="nom_s"),
 
796
        'product_amc': fields.related('product_id', 'product_amc', type='float', string='AMC'),
 
797
        'reviewed_consumption': fields.related('product_id', 'reviewed_consumption', type='float', string='FMC'),
 
798
        'currency_id': fields.related('product_id', 'currency_id', type='many2one', relation='res.currency', string='Func. cur.'),
 
799
        'cost_price': fields.related('product_id', 'standard_price', type='float', string='Cost price'),
 
800
        'uom_id': fields.related('product_id', 'uom_id', type='many2one', relation='product.uom', string='UoM',
 
801
                                store={'product.template': (_get_template, ['type'], 10)}),
 
802
        'mission_report_id': fields.many2one('stock.mission.report', string='Mission Report', required=True),
 
803
        'internal_qty': fields.float(digits=(16,2), string='Instance Stock'),
 
804
        'internal_val': fields.function(_get_internal_val, method=True, type='float', string='Instance Stock Val.'),
 
805
        #'internal_val': fields.float(digits=(16,2), string='Instance Stock Val.'),
 
806
        'stock_qty': fields.float(digits=(16,2), string='Stock Qty.'),
 
807
        'stock_val': fields.float(digits=(16,2), string='Stock Val.'),
 
808
        'central_qty': fields.float(digits=(16,2), string='Unallocated Stock Qty.'),
 
809
        'central_val': fields.float(digits=(16,2), string='Unallocated Stock Val.'),
 
810
        'wh_qty': fields.function(_get_wh_qty, method=True, type='float', string='Warehouse stock',
 
811
                                  store={'stock.mission.report.line': (lambda self, cr, uid, ids, c=None: ids, ['stock_qty', 'central_qty'], 10),}),
 
812
        'cross_qty': fields.float(digits=(16,3), string='Cross-docking Qty.'),
 
813
        'cross_val': fields.float(digits=(16,3), string='Cross-docking Val.'),
 
814
        'secondary_qty': fields.float(digits=(16,2), string='Secondary Stock Qty.'),
 
815
        'secondary_val': fields.float(digits=(16,2), string='Secondary Stock Val.'),
 
816
        'cu_qty': fields.float(digits=(16,2), string='Internal Cons. Unit Qty.'),
 
817
        'cu_val': fields.float(digits=(16,2), string='Internal Cons. Unit Val.'),
 
818
        'in_pipe_qty': fields.float(digits=(16,2), string='In Pipe Qty.'),
 
819
        'in_pipe_val': fields.float(digits=(16,2), string='In Pipe Val.'),
 
820
        'in_pipe_coor_qty': fields.float(digits=(16,2), string='In Pipe from Coord.'),
 
821
        'in_pipe_coor_val': fields.float(digits=(16,2), string='In Pipe from Coord.'),
 
822
        'updated': fields.boolean(string='Updated'),
 
823
        'full_view': fields.related('mission_report_id', 'full_view', string='Full view', type='boolean', store=True),
 
824
        'move_ids': fields.many2many('stock.move', 'mission_line_move_rel', 'line_id', 'move_id', string='Noves'),
 
825
    }
 
826
 
 
827
    _defaults = {
 
828
        'internal_qty': 0.00,
 
829
        'internal_val': 0.00,
 
830
        'stock_qty': 0.00,
 
831
        'stock_val': 0.00,
 
832
        'wh_qty': 0.00,
 
833
        'central_qty': 0.00,
 
834
        'central_val': 0.00,
 
835
        'cross_qty': 0.00,
 
836
        'cross_val': 0.00,
 
837
        'secondary_qty': 0.00,
 
838
        'secondary_val': 0.00,
 
839
        'cu_qty': 0.00,
 
840
        'cu_val': 0.00,
 
841
        'in_pipe_qty': 0.00,
 
842
        'in_pipe_val': 0.00,
 
843
        'in_pipe_coor_qty': 0.00,
 
844
        'in_pipe_coor_val': 0.00,
 
845
    }
 
846
 
 
847
    def update_full_view_line(self, cr, uid, ids, context=None):
 
848
        is_project = False
 
849
        if self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.instance_id.level == 'project':
 
850
            is_project = True
 
851
 
 
852
 
 
853
        request = '''SELECT l.product_id AS product_id,
 
854
                            sum(l.internal_qty) AS internal_qty,
 
855
                            sum(l.stock_qty) AS stock_qty,
 
856
                            sum(l.central_qty) AS central_qty,
 
857
                            sum(l.cross_qty) AS cross_qty,
 
858
                            sum(l.secondary_qty) AS secondary_qty,
 
859
                            sum(l.cu_qty) AS cu_qty,
 
860
                            sum(l.in_pipe_qty) AS in_pipe_qty,
 
861
                            sum(l.in_pipe_coor_qty) AS in_pipe_coor_qty,
 
862
                            sum(l.internal_qty)*t.standard_price AS internal_val
 
863
                     FROM stock_mission_report_line l
 
864
                       LEFT JOIN
 
865
                          stock_mission_report m
 
866
                       ON l.mission_report_id = m.id
 
867
                       LEFT JOIN
 
868
                          product_product p
 
869
                       ON l.product_id = p.id
 
870
                       LEFT JOIN
 
871
                          product_template t
 
872
                       ON p.product_tmpl_id = t.id
 
873
                     WHERE m.full_view = False
 
874
                       AND (l.internal_qty != 0.00
 
875
                       OR l.stock_qty != 0.00
 
876
                       OR l.central_qty != 0.00
 
877
                       OR l.cross_qty != 0.00
 
878
                       OR l.secondary_qty != 0.00
 
879
                       OR l.cu_qty != 0.00
 
880
                       OR l.in_pipe_qty != 0.00
 
881
                       OR l.in_pipe_coor_qty != 0.00)
 
882
                     GROUP BY l.product_id, t.standard_price'''
 
883
 
 
884
        cr.execute(request)
 
885
 
 
886
        vals = cr.fetchall()
 
887
        mission_report_id = self.pool.get('stock.mission.report').search(cr, uid, [('full_view', '=', True)], context=context)
 
888
        for line in vals:
 
889
            line_ids = self.search(cr, uid, [('mission_report_id.full_view', '=', True), ('product_id', '=', line[0])], context=context)
 
890
            if not line_ids:
 
891
                if not mission_report_id:
 
892
                    continue
 
893
                line_id = self.create(cr, uid, {'mission_report_id': mission_report_id[0],
 
894
                                                'product_id': line[0]}, context=context)
 
895
            else:
 
896
                line_id = line_ids[0]
 
897
 
 
898
            in_pipe = line[7] or 0.00
 
899
            if not is_project:
 
900
                in_pipe = (line[7] or 0.00) - (line[8] or 0.00)
 
901
 
 
902
            self.write(cr, uid, [line_id], {'internal_qty': line[1] or 0.00,
 
903
                                            'internal_val': line[9] or 0.00,
 
904
                                            'stock_qty': line[2] or 0.00,
 
905
                                            'central_qty': line[3] or 0.00,
 
906
                                            'cross_qty': line[4] or 0.00,
 
907
                                            'secondary_qty': line[5] or 0.00,
 
908
                                            'cu_qty': line[6] or 0.00,
 
909
                                            'in_pipe_qty': line[7] or 0.00,
 
910
                                            'in_pipe_coor_qty': line[8] or 0.00,}, context=context)
 
911
 
 
912
        return True
 
913
 
 
914
stock_mission_report_line()