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

2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
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
from datetime import datetime
24
from tools.translate import _
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
25
from mx.DateTime import *
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
26
27
import time
28
import pooler
29
import netsvc
30
31
32
33
class procurement_order(osv.osv):
34
    _name = 'procurement.order'
35
    _inherit = 'procurement.order'
36
    
37
    def run_automatic_cycle(self, cr, uid, use_new_cursor=False, context={}):
38
        '''
39
        Create procurement on fixed date
40
        '''
41
        if use_new_cursor:
42
            cr = pooler.get_db(use_new_cursor).cursor()
43
            
44
        request_obj = self.pool.get('res.request')
45
        cycle_obj = self.pool.get('stock.warehouse.order.cycle')
46
        proc_obj = self.pool.get('procurement.order')
47
        product_obj = self.pool.get('product.product')
73.1.4 by jf
UF-73
48
        freq_obj = self.pool.get('stock.frequence')
49
50
        start_date = datetime.now()
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
51
        
73.1.4 by jf
UF-73
52
        cycle_ids = cycle_obj.search(cr, uid, [('next_date', '<=', start_date.strftime('%Y-%m-%d'))])
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
53
        
54
        created_proc = []
55
        report = []
56
        report_except = 0
57
        
73.1.4 by jf
UF-73
58
        # Cache for product/location
59
        cache = {}
60
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
61
        
62
        # We start with only category Automatic Supply
63
        for cycle in cycle_obj.browse(cr, uid, cycle_ids):
64
            # We define the replenish location
65
            location_id = False
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
66
            if not cycle.location_id or not cycle.location_id.id:
67
                location_id = cycle.warehouse_id.lot_input_id.id
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
68
            else:
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
69
                location_id = cycle.location_id.id
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
70
                
71
            d_values = {'leadtime': cycle.leadtime,
72
                        'coverage': cycle.order_coverage,
73
                        'safety_time': cycle.safety_stock_time,
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
74
                        'safety': cycle.safety_stock,
75
                        'past_consumption': cycle.past_consumption,
76
                        'reviewed_consumption': cycle.reviewed_consumption,
77
                        'manual_consumption': cycle.manual_consumption,}
73.1.4 by jf
UF-73
78
79
            if not cycle.product_id:
80
                not_products = []
81
                for p in cycle.product_ids:
82
                    not_products.append(p.id)
83
84
                product_ids = product_obj.search(cr, uid, [('categ_id', 'child_of', cycle.category_id.id), ('id', 'not in', not_products)])
85
                
86
                for product in product_obj.browse(cr, uid, product_ids):
87
                    proc_id = self.create_proc_cycle(cr, uid, cycle, product.id, location_id, d_values, cache=cache)
88
                    
89
90
                    if proc_id:
91
                        created_proc.append(proc_id)
92
            else:
93
                proc_id = self.create_proc_cycle(cr, uid, cycle, cycle.product_id.id, location_id, d_values, cache=cache)
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
94
                
95
                if proc_id:
96
                    created_proc.append(proc_id)
97
        
73.1.4 by jf
UF-73
98
            if cycle.frequence_id:
99
                freq_obj.write(cr, uid, cycle.frequence_id.id, {'last_run': start_date.strftime('%Y-%m-%d')})
100
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
101
                    
102
        for proc in proc_obj.browse(cr, uid, created_proc):
103
            if proc.state == 'exception':
104
                report.append('PROC %d: from stock - %3.2f %-5s - %s' % \
105
                               (proc.id, proc.product_qty, proc.product_uom.name,
106
                                proc.product_id.name,))
107
                report_except += 1
108
                
109
        end_date = datetime.now()
110
                
111
        summary = '''Here is the procurement scheduling report for Order Cycle
112
113
        Start Time: %s
114
        End Time: %s
115
        Total Procurements processed: %d
116
        Procurements with exceptions: %d
73.1.4 by jf
UF-73
117
        \n'''% (start_date, end_date, len(created_proc), report_except)
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
118
        summary += '\n'.join(report)
73.1.4 by jf
UF-73
119
        req_id = request_obj.create(cr, uid,
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
120
                {'name': "Procurement Processing Report.",
121
                 'act_from': uid,
122
                 'act_to': uid,
123
                 'body': summary,
124
                })
73.1.4 by jf
UF-73
125
        if req_id:
126
            request_obj.request_send(cr, uid, [req_id])
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
127
        
128
        if use_new_cursor:
129
            cr.commit()
130
            cr.close()
131
            
132
        return {}
133
    
73.1.4 by jf
UF-73
134
    def create_proc_cycle(self, cr, uid, cycle, product_id, location_id, d_values={}, cache={}, context={}):
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
135
        '''
136
        Creates a procurement order for a product and a location
137
        '''
138
        proc_obj = self.pool.get('procurement.order')
139
        cycle_obj = self.pool.get('stock.warehouse.order.cycle')
140
        product_obj = self.pool.get('product.product')
141
        wf_service = netsvc.LocalService("workflow")
142
        report = []
143
        proc_id = False
144
        
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
145
        if isinstance(product_id, (int, long)):
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
146
            product_id = [product_id]
147
        
148
        product = product_obj.browse(cr, uid, product_id[0])
149
        
150
        # Enter the stock location in cache to know which products has been already replenish for this location
151
        if not cache.get(location_id, False):
152
            cache.update({location_id: []})
153
        
154
        # If a rule already exist for the category of the product or for the product
73.1.4 by jf
UF-73
155
        # itself for the same location, we don't create a procurement order
156
        #cycle_ids = cycle_obj.search(cr, uid, [('category_id', '=', product.categ_id.id), ('product_id', '=', False), ('location_id', '=', location_id), ('id', '!=', cycle.id)])
157
        #cycle2_ids = cycle_obj.search(cr, uid, [('product_id', '=', product.id), ('location_id', '=', location_id), ('id', '!=', cycle.id)])
158
        #if cycle_ids:
159
        #    cr.execute('''SELECT order_cycle_id
160
        #                FROM order_cycle_product_rel
161
        #                WHERE order_cycle_id in %s
162
        #                AND product_id = %s''', (tuple(cycle_ids), product.id))
163
        #    res = cr.fetchall()
164
        #    for r in res:
165
        #        cycle_ids.remove(r[0])
166
        #if cycle2_ids or cycle_ids:
167
        #    return False
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
168
        
169
            
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
170
        if product.id not in cache.get(location_id):
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
171
            newdate = datetime.today()
73.1.4 by jf
UF-73
172
            quantity_to_order = self._compute_quantity(cr, uid, cycle, product.id, location_id, d_values)
93.6.12 by Quentin THEURET
UF-212: [FIX] Changed in quantity calculation, the delivery lead time in month instead of days - Changed also unittest
173
                
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
174
            if quantity_to_order <= 0:
175
                return False
176
            else:
177
                proc_id = proc_obj.create(cr, uid, {
178
                                        'name': _('Automatic Supply: %s') % (cycle.name,),
179
                                        'origin': cycle.name,
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
180
                                        'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
181
                                        'product_id': product.id,
182
                                        'product_qty': quantity_to_order,
183
                                        'product_uom': product.uom_id.id,
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
184
                                        'location_id': location_id,
185
                                        'procure_method': 'make_to_order',
186
                })
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
187
                wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
188
                wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_check', cr)
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
189
                context.update({'button': 'scheduler'})
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
190
                cycle_obj.write(cr, uid, [cycle.id], {'procurement_id': proc_id}, context=context)
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
191
            
192
            # Fill the cache
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
193
            cache.get(location_id).append(product.id)
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
194
        
195
        return proc_id
196
    
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
197
    def _compute_quantity(self, cr, uid, cycle_id, product_id, location_id, d_values={}, context={}):
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
198
        '''
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
199
        Compute the quantity of product to order like thid :
200
            [Delivery lead time (from supplier tab of the product or by default or manually overwritten) x Monthly Consumption]
201
            + Order coverage (number of months : 3 by default, manually overwritten) x Monthly consumption
202
            - Projected available quantity
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
203
        '''
204
        product_obj = self.pool.get('product.product')
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
205
        supplier_info_obj = self.pool.get('product.supplierinfo')
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
206
        location_obj = self.pool.get('stock.location')
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
207
        cycle_obj = self.pool.get('stock.warehouse.order.cycle')
243.3.10 by Quentin THEURET
UF-385 [IMP] Modified unit tests of Order Cycle to implement consumption calculation management on them
208
        review_obj = self.pool.get('monthly.review.consumption')
209
        review_line_obj = self.pool.get('monthly.review.consumption.line')
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
210
        
211
        product = product_obj.browse(cr, uid, product_id)
212
        location = location_obj.browse(cr, uid, location_id)
213
214
        
215
        # Get the delivery lead time
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
216
        delivery_leadtime = product.seller_delay and product.seller_delay != 'N/A' and round(int(product.seller_delay)/30.0, 2) or 1
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
217
        if 'leadtime' in d_values and d_values.get('leadtime', 0.00) != 0.00:
93.6.12 by Quentin THEURET
UF-212: [FIX] Changed in quantity calculation, the delivery lead time in month instead of days - Changed also unittest
218
            delivery_leadtime = d_values.get('leadtime')
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
219
        else:
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
220
            sequence = False
221
            for supplier_info in product.seller_ids:
222
                if sequence and supplier_info.sequence < sequence:
223
                    sequence = supplier_info.sequence
243.3.10 by Quentin THEURET
UF-385 [IMP] Modified unit tests of Order Cycle to implement consumption calculation management on them
224
                    delivery_leadtime = round(supplier_info.delay/30.0, 2)
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
225
                elif not sequence:
226
                    sequence = supplier_info.sequence
243.3.10 by Quentin THEURET
UF-385 [IMP] Modified unit tests of Order Cycle to implement consumption calculation management on them
227
                    delivery_leadtime = round(supplier_info.delay/30.0, 2)
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
228
                
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
229
        # Get the monthly consumption
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
230
        monthly_consumption = 0.00
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
231
        
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
232
        if 'reviewed_consumption' in d_values and d_values.get('reviewed_consumption'):
358.4.5 by Quentin THEURET
UF-519-520 [FIX] Fixed errors on unit tests
233
            review_ids = review_obj.search(cr, uid, [], order='period_to', context=context)
243.3.10 by Quentin THEURET
UF-385 [IMP] Modified unit tests of Order Cycle to implement consumption calculation management on them
234
            review_line_ids = review_line_obj.search(cr, uid, [('mrc_id', 'in', review_ids), ('name', '=', product_id)], context=context)
235
            for line in review_line_obj.browse(cr, uid, review_line_ids, context=context):
236
                last_date = False
237
                if not last_date or last_date < line.mrc_id.period_to:
238
                    monthly_consumption = line.fmc
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
239
        elif 'monthly_consumption' in d_values and d_values.get('monthly_consumption'):
243.3.10 by Quentin THEURET
UF-385 [IMP] Modified unit tests of Order Cycle to implement consumption calculation management on them
240
            monthly_consumption = product_obj.compute_amc(cr, uid, product.id, context=context)
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
241
        else:
242
            monthly_consumption = d_values.get('manual_consumption', 0.00)
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
243
            
244
        # Get the order coverage
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
245
        order_coverage = d_values.get('coverage', 3)
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
246
        
247
        # Get the projected available quantity
248
        available_qty = self.get_available(cr, uid, product_id, location_id, monthly_consumption, d_values)
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
249
        
358.4.5 by Quentin THEURET
UF-519-520 [FIX] Fixed errors on unit tests
250
        qty_to_order = (delivery_leadtime * monthly_consumption) + (order_coverage * monthly_consumption) - available_qty
251
        
252
        return round(self.pool.get('product.uom')._compute_qty(cr, uid, product.uom_id.id, qty_to_order, product.uom_id.id), 2)
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
253
        
254
        
255
    def get_available(self, cr, uid, product_id, location_id, monthly_consumption, d_values={}, context={}):
256
        '''
257
        Compute the projected available quantity like this :
258
            Available stock (real stock - picked reservation)
259
            + Quantity on order ("in pipe")
260
            - Safety stock [blank by default but can be overwritten for a product category or at product level]
261
            - Safety time [= X (= 0 by default) month x Monthly consumption (validated consumption by default or
262
                        manually overwritten for a product or at product level)]
263
            - Expiry quantities.
264
        '''
265
        product_obj = self.pool.get('product.product')
266
        location_obj = self.pool.get('stock.location')
267
        move_obj = self.pool.get('stock.move')
268
        
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
269
        context.update({'location': location_id,
270
                        'compute_child': True, 
271
                        'from_date': time.strftime('%Y-%m-%d')})
272
        
273
        product = product_obj.browse(cr, uid, product_id, context=context)
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
274
        location_name = location_obj.browse(cr, uid, location_id, context=context).name
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
275
        
276
        ''' Set this part of algorithm as comments because this algorithm seems to be equal to virtual stock
277
        
278
            To do validate by Magali
279
            
280
            Picked reservation will be developed on future sprint
281
        ''' 
282
        
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
283
        # Get the available stock
284
        # Get the real stock
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
285
        picked_resa = product_obj.get_product_available(cr, uid, [product_id], context={'states': ['assigned'],
286
                                                                                       'what': ('in, out'), 
287
                                                                                       'location': location_id,
288
                                                                                       'compute_child': True, 
289
                                                                                       'from_date': time.strftime('%Y-%m-%d')})
290
        # Get the picked reservation
291
        ## TODO: To confirm by Magali
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
292
#        picked_reservation = 0.00
293
#        move_ids = []
294
#        for location in location_obj.search(cr, uid, [('location_id', 'child_of', [location_id])]):
295
#            for move_id in move_obj.search(cr, uid, [('product_id', '=', product_id), ('location_dest_id', '=', location), 
296
#                                                     ('state', '!=', 'draft'), ('move_dest_id', '!=', False)]):
297
#                move_ids.append(move_id)
298
#            
299
#        for move in move_obj.browse(cr, uid, move_ids):
300
#            picked_reservation += move.product_qty
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
301
            
302
        available_stock = product.qty_available - picked_resa.get(product.id)
303
        
304
        #available_stock = real_stock.get(product_id) - picked_reservation
305
        
306
        # Get the quantity on order
307
        ## TODO : To confirm by Magali
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
308
#        quantity_on_order = 0.00
309
#        move_ids = []
310
#        for location in location_obj.search(cr, uid, [('location_id', 'child_of', [location_id])]):
311
#            for move_id in move_obj.search(cr, uid, [('product_id', '=', product_id), ('location_dest_id', '=', location)]):
312
#                move_ids.append(move_id)
313
#            
314
#        for move in move_obj.browse(cr, uid, move_ids):
315
#            quantity_on_order += move.product_qty
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
316
            
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
317
        quantity_on_order = product_obj.get_product_available(cr, uid, [product_id], context={'states': ['confirmed'],
318
                                                                                              'what': ('in, out'), 
319
                                                                                              'location': location_id,
320
                                                                                              'compute_child': True, 
321
                                                                                              'from_date': time.strftime('%Y-%m-%d')})
322
           
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
323
        # Get the safety stock
324
        safety_stock = d_values.get('safety', 0)
325
        
326
        # Get the safety time
327
        safety_time = d_values.get('safety_time', 0)
328
        
329
        # Get the expiry quantity
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
330
        # Set as comment because expiry quantity will be developed in a future sprint
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
331
        expiry_quantity = product_obj.get_expiry_qty(cr, uid, product_id, location_id, monthly_consumption, d_values)
332
        expiry_quantity = expiry_quantity and available_stock - expiry_quantity or 0.00
333
        #expiry_quantity = 0.00
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
334
        
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
335
        # Set this part of algorithm as comments because this algorithm seems to be equal to virtual stock
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
336
        return available_stock + quantity_on_order.get(product.id) - safety_stock - (safety_time * monthly_consumption) - expiry_quantity
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
337
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
338
#        return product.virtual_available - safety_stock - (safety_time * monthly_consumption) - expiry_quantity
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
339
     
340
     
341
    def get_expiry_qty(self, cr, uid, product_id, location_id, monthly_consumption, d_values={}, context={}):
342
        '''
343
        Compute the expiry quantities
2.17.6 by Quentin THEURET
UF-73: [IMP] Fixed error on quantity computation
344
        
345
        INFO : This method is not use on Sprint1 because the algorithm is
346
        not determined
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
347
        '''
348
        product_obj = self.pool.get('product.product')
349
        stock_obj = self.pool.get('stock.location')
350
        batch_obj = self.pool.get('stock.production.lot')
351
        move_obj = self.pool.get('stock.move')
352
        
353
        res = 0.00
354
        
355
        location_ids = stock_obj.search(cr, uid, [('location_id', 'child_of', location_id)])
356
        available_stock = 0.00
357
        
358
        # Get all batches for this product
359
        batch_ids = batch_obj.search(cr, uid, [('product_id', '=', product_id)], offset=0, limit=None, order='life_date')
360
        if len(batch_ids) == 1:
361
            # Search all moves with this batch number
362
            for location in location_ids:
363
                context.update({'location_id': location})
364
                available_stock += batch_obj.browse(cr, uid, batch_ids, context=context)[0].stock_available
365
            expiry_date = batch_obj.browse(cr, uid, batch_ids)[0].life_date or time.strftime('%Y-%m-%d')
366
            nb_month = self.get_diff_date(expiry_date)
367
            res = available_stock - (nb_month * monthly_consumption)
368
        else:
369
            # Get the stock available for the product
370
            for location in location_ids:
371
                context.update({'location_id': location})
372
                for batch in batch_obj.browse(cr, uid, batch_ids, context=context):
373
                    available_stock += batch.stock_available
374
                    
375
            last_nb_month = 0
376
            sum_nb_month = 0
377
            res = 0
378
            for batch in batch_obj.browse(cr, uid, batch_ids):
379
                nb_month = self.get_diff_date(batch.life_date)
380
                if (nb_month - sum_nb_month) > 0:
381
                    tmp_qty = (nb_month - sum_nb_month) * monthly_consumption 
382
                    res += available_stock - (last_nb_month * monthly_consumption) - tmp_qty
383
                else:
384
                    break 
385
            
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
386
        return res
387
    
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
388
    def get_diff_date(self, date):
389
        '''
390
        Returns the number of month between the date in parameter and today
391
        '''
392
        date = Parser.DateFromString(date)
243.3.34 by Quentin THEURET
UF-404 [IMP] Integrated the consumption calculation + expiry quantities in procurement_cycle reordered quantity calculation
393
        today = datetime.today()
2.17.5 by Quentin THEURET
UF-113: [ADD] Added procurement_cycle module
394
        
395
        # The batch is expired
396
        if date.year < today.year or (date.year == today.year and date.month < today.month):
397
            return 0 
398
        
399
        # The batch expires this month
400
        if date.year == today.year and date.month == today.month:
401
            return 0
402
        
403
        # The batch expires in one month
404
        if date.year == today.year and date.month == today.month+1 and date.day >= today.day:
405
            return 0
406
        
407
        # Compute the number of months
408
        nb_month = 0
409
        nb_month += (date.year - today.year) * 12
410
        nb_month += date.month - today.month
411
        if date.day < today.day:
412
            nb_month -= 1
413
            
414
        return nb_month
2.17.3 by Quentin THEURET
UF-73: [ADD] Added product_consumption module to compute the monthly consumption of a product
415
        
416
procurement_order()
417
73.1.3 by jf
UF-43 [FIX] bugs, rewrite of compute next date
418
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: