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:
|