Merge lp:~openbig/bigconsulting/order_point_calcultor into lp:bigconsulting

Proposed by gpa(OpenERP)
Status: Superseded
Proposed branch: lp:~openbig/bigconsulting/order_point_calcultor
Merge into: lp:bigconsulting
Diff against target: 445 lines (+232/-132)
4 files modified
packing_barcode_check/packing_barcode_check.py (+2/-2)
packing_barcode_check/wizard/select_picking.py (+1/-0)
stock_minimum_calculator/stock_minimum_calculator_wizard.xml (+1/-1)
stock_minimum_calculator/wizard/stock_order_point_calculator.py (+228/-129)
To merge this branch: bzr merge lp:~openbig/bigconsulting/order_point_calcultor
Reviewer Review Type Date Requested Status
openbig Pending
Review via email: mp+32757@code.launchpad.net

This proposal supersedes a proposal from 2010-08-16.

This proposal has been superseded by a proposal from 2010-08-17.

Description of the change

improvement in order point calculator wizard bug 615927

To post a comment you must log in.
82. By gpa(OpenERP)

improvement for automatically increment in scanned quantity and real quantity

83. By gpa(OpenERP)

changes in first condition of date

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'packing_barcode_check/packing_barcode_check.py'
2--- packing_barcode_check/packing_barcode_check.py 2010-08-11 12:37:21 +0000
3+++ packing_barcode_check/packing_barcode_check.py 2010-08-17 04:46:40 +0000
4@@ -31,8 +31,8 @@
5 def _compute_quantity(self, cr, uid, ids, fieldnames, args, context=None):
6 res = {}
7 for obj in self.browse(cr, uid, ids, context=context):
8- total_quantity = sum(move_id.product_qty for move_id in obj.move_lines)
9- scanned_quantity = sum(scan.scan_quantity for scan in obj.scaned_ids)
10+ total_quantity = sum(to_be_id.quantity for to_be_id in obj.tobe_scan_ids)
11+ scanned_quantity = sum(to_be_id.scan_quantity for to_be_id in obj.tobe_scan_ids)
12 res[obj.id] = {
13 'total_quantity' : total_quantity,
14 'scanned_quantity' : scanned_quantity,
15
16=== modified file 'packing_barcode_check/wizard/select_picking.py'
17--- packing_barcode_check/wizard/select_picking.py 2010-08-11 13:15:42 +0000
18+++ packing_barcode_check/wizard/select_picking.py 2010-08-17 04:46:40 +0000
19@@ -47,6 +47,7 @@
20 'res_model': 'stock.picking',
21 'type': 'ir.actions.act_window',
22 'view_id':[resource_id],
23+ 'auto_refresh':1,
24 'res_id':data['form']['picking_id'],
25 'context':"{'contact_display':'partner'}",
26 }
27
28=== modified file 'stock_minimum_calculator/stock_minimum_calculator_wizard.xml'
29--- stock_minimum_calculator/stock_minimum_calculator_wizard.xml 2010-07-27 09:27:59 +0000
30+++ stock_minimum_calculator/stock_minimum_calculator_wizard.xml 2010-08-17 04:46:40 +0000
31@@ -9,7 +9,7 @@
32 id="id_set_seasonal_trend"/>
33 <wizard
34 string="Order Point Cacluator"
35- model="product.product"
36+ model="res.partner"
37 name="orderpoint.calculator"
38 menu="True"
39 id="id_order_point_cacluator"/>
40
41=== modified file 'stock_minimum_calculator/wizard/stock_order_point_calculator.py'
42--- stock_minimum_calculator/wizard/stock_order_point_calculator.py 2010-08-04 13:12:02 +0000
43+++ stock_minimum_calculator/wizard/stock_order_point_calculator.py 2010-08-17 04:46:40 +0000
44@@ -34,13 +34,9 @@
45 <field name="warehouse_id"/>
46 <field name="location_id"/>
47 <field name="seasonal_id"/>
48+ <field name="max_qty_factor"/>
49 <field name="delactive"/>
50 <field name="method_qty_calculation" colspan="4"/>
51- <group attrs="{'invisible':[('method_qty_calculation','=','his_cons_without_product')]}" colspan="4">
52- <separator string="Configuration of Base Consumptions Periods" colspan="4"/>
53- <field name="date_start"/>
54- <field name="date_stop"/>
55- </group>
56 </form>"""
57
58 orderpoint_calculator_fields = {
59@@ -70,24 +66,19 @@
60 'required': True,
61 'help':'Use this field as index. Reference index is Main Season with 1.00. If you want to change the orderpoint rules you are able to define new season with a seasonal index. This index should reference to 1.00. For example if you expect - 10% consumption for autumn season in comparition to main season enter 0.90.'
62 },
63-
64- 'date_start': {
65- 'string':'From Date',
66- 'type':'date'
67- },
68-
69- 'date_stop': {
70- 'string':'To Date',
71- 'type':'date',
72- 'default': lambda *a: time.strftime('%Y-%m-%d')
73+
74+ 'max_qty_factor': {
75+ 'string':'Max. Qty. Factor',
76+ 'type':'float',
77+ 'required': True
78 },
79
80 'method_qty_calculation':{
81 'string':"Method Calculation",
82 'type':'selection',
83- 'selection':[('his_cons_with_product', 'Calculate with historical consumptions of products'),
84+ 'selection':[('his_cons_with_product', 'Calculate with planning values'),
85 ('his_cons_without_product', 'Calculate with Out historical consumptions of product'),
86- ('hist_cons_and_open_sale', 'Calculate with historical consumptions of product and Open sales orders'),
87+ ('hist_cons_and_open_sale', 'Calculate with historical values'),
88 ],'required': True,
89 'default': lambda *a:'his_cons_with_product'
90 },
91@@ -116,16 +107,98 @@
92
93 return {'warehouse_id': warehouse_id, 'location_id':location_id,'date_start':from_date,'seasonal_id':seasonal_id}
94
95+
96+def _sale_consume_qty(self, cr, uid, product_id, from_date, to_date, state, context):
97+ """calculation of consumption of product from_date to to_date , where state is done """
98+
99+ pool = pooler.get_pool(cr.dbname)
100+
101+ sale_obj = pool.get('sale.order')
102+ sale_line_obj = pool.get("sale.order.line")
103+ consum_qty = 0.0
104+ sale_ids = sale_obj.search(cr,uid,[('date_order','>=',from_date),('date_order','<=',to_date), ('state','=',state)])
105+ if sale_ids:
106+ for sid in sale_ids:
107+ sale_line_id = sale_line_obj.search(cr,uid,[('order_id','=',sid),('product_id','=',product_id)])
108+ for line_id in sale_line_id:
109+ sale_line_data= sale_line_obj.browse(cr, uid, line_id, context=context).product_uom_qty
110+ consum_qty += sale_line_data
111+
112+ return consum_qty
113+
114+def _sale_open_qty(self, cr, uid, product_id, state, context):
115+ """Calculation of open sale orders"""
116+
117+ pool = pooler.get_pool(cr.dbname)
118+
119+ sale_obj = pool.get('sale.order')
120+ sale_line_obj = pool.get("sale.order.line")
121+ open_sale_qty = 0.0
122+ open_sale_ids = sale_obj.search(cr, uid, [('state','in',state)])
123+ if open_sale_ids:
124+ for sale_id in open_sale_ids:
125+ sale_open_line_ids = sale_line_obj.search(cr,uid,[('order_id','=',sale_id),('product_id','=',product_id)])
126+ for open_line_id in sale_open_line_ids:
127+ sale_line_data= sale_line_obj.browse(cr,uid,open_line_id)
128+ open_sale_qty += sale_line_data.product_uom_qty
129+
130+ return open_sale_qty
131+
132+def _purchase_open_qty(self, cr, uid, product_id, state, context):
133+ """ Calculation of open purchase orders """
134+
135+ pool = pooler.get_pool(cr.dbname)
136+
137+ purchase_obj = pool.get('purchase.order')
138+ purchase_order_line_obj = pool.get('purchase.order.line')
139+ open_purchase_qty = 0.0
140+ open_purchase_ids = purchase_obj.search(cr,uid,[('state','=',state)])
141+ if open_purchase_ids:
142+ for purchase_id in open_purchase_ids:
143+ open_purchase_line_ids= purchase_order_line_obj.search(cr,uid,[('order_id','=',purchase_id),('product_id','=',product_id)])
144+ for open_pur_id in open_purchase_line_ids:
145+ purchase_line_data = purchase_order_line_obj.browse(cr, uid, open_pur_id, context=context)
146+ open_purchase_qty += purchase_line_data.product_qty
147+
148+ return open_purchase_qty
149+
150+def _refund_qty(self, cr, uid, product_id, from_date, to_date, state, context):
151+ """ Calculation of the refund quantities of the prduct from the refund invoice, between from_date, to_date"""
152+
153+ pool = pooler.get_pool(cr.dbname)
154+
155+ account_invoice_obj = pool.get('account.invoice')
156+ account_invoice_line_obj = pool.get('account.invoice.line')
157+ refund_qty = 0.0
158+ refund_invoice_ids = account_invoice_obj.search(cr,uid,[('type','in',state),('date_invoice','>=',from_date),('date_invoice','<=',to_date)])
159+ for refund_id in refund_invoice_ids:
160+ invoie_line_ids = account_invoice_line_obj.search(cr,uid,[('invoice_id','=',refund_id),('product_id','=',product_id)])
161+ for invoice_line_id in invoie_line_ids:
162+ inovice_line_data = account_invoice_line_obj.browse(cr, uid, invoice_line_id, context=context).quantity
163+ refund_qty += inovice_line_data
164+
165+ return refund_qty
166+
167+
168+def _date_diff(self, cr, uid, product_id, from_date, to_date, context):
169+ """ Date difference between from_date and to_date """
170+
171+ first_date = time.mktime(time.strptime(from_date,'%Y-%m-%d %H:%M:%S'))
172+ last_date = time.mktime(time.strptime(to_date,'%Y-%m-%d %H:%M:%S'))
173+ diff_day = (last_date-first_date)/(3600*24)
174+ return diff_day
175+
176 def _do_calculate(self, cr, uid, data, context):
177 pool = pooler.get_pool(cr.dbname)
178
179 purchase_obj = pool.get('purchase.order')
180- sale_obj = pool.get('sale.order')
181 product_obj = pool.get('product.product')
182 supp_obj = pool.get('product.supplierinfo')
183 supp_cost_opt_obj = pool.get('supplier.cost.opti.lead.time')
184 min_rule_obj = pool.get('stock.warehouse.orderpoint')
185 seasonal_obj = pool.get('product.seasonal')
186+ stock_move_obj = pool.get('stock.move')
187+
188 ##### Calculation of purchase lead time
189 purchase_lead_time = 0.0
190 company = pool.get('res.users').browse(cr, uid, uid, context).company_id
191@@ -135,117 +208,143 @@
192 seasonal_id = data['form']['seasonal_id']
193 seasonal_data = seasonal_obj.browse(cr, uid, seasonal_id)
194 seasonal_factor = seasonal_data.seasonal_factor
195-
196- ##### Calculation of supplier lead time
197-
198- for id in data['ids']:
199- product_id = product_obj.browse(cr, uid, id, context)
200- supplier_lead_time = 0.0
201- if product_id:
202- for supp in product_id.seller_ids:
203- sup = supp_obj.browse(cr, uid, supp.id, context)
204- supplier_lead_time = sup.delay
205-
206- ###### Calculation of average_daily_consumption
207- date_start = data['form']['date_start']
208- date_stop = data['form']['date_stop']
209- average_daily_consumption = 0.0
210- sale_line_obj = pool.get("sale.order.line")
211- consum_qty = 0.0
212- sale_ids = sale_obj.search(cr,uid,[('date_order','>=',date_start),('date_order','<=',date_stop)])
213- if sale_ids:
214- for sid in sale_ids:
215- sale_line_id = sale_line_obj.search(cr,uid,[('order_id','=',sid),('product_id','=',product_id.id)])
216- for line_id in sale_line_id:
217- sale_line_data= sale_line_obj.browse(cr,uid,line_id)
218- consum_qty += sale_line_data.product_uom_qty
219- ###here consume quantity is total of selected product
220- ##################calculation of date difference between first and last sale order
221- sale_ids = sale_obj.search(cr,uid,[('date_order','>=',date_start),('date_order','<=',date_stop)], order='date_order asc')
222- if sale_ids:
223- start_sale_id = sale_ids[0]
224- last_sale_id = sale_ids[-1]
225- first_sale_date = sale_obj.browse(cr,uid,start_sale_id).date_order
226- last_sale_date = sale_obj.browse(cr,uid,last_sale_id).date_order
227- first_date = time.mktime(time.strptime(first_sale_date,'%Y-%m-%d'))
228- last_date = time.mktime(time.strptime(last_sale_date,'%Y-%m-%d'))
229- diff_day = (last_date-first_date)/(3600*24)
230- if diff_day > 0:
231- average_daily_consumption = consum_qty / diff_day
232- ###### Calculation of plan_average_daily_consumption
233- plan_average_daily_consumption = 0.0
234- if product_id.plan_avg_consume:
235- plan_average_daily_consumption = product_id.plan_avg_consume
236-
237- ####### get location #####
238- location_id = data['form']['location_id']
239-
240- ########## calculation historical consumption of products and open sales orders“
241- ### total sale qty with open state
242-
243- sale_qty = 0.0
244- open_sale_ids = sale_obj.search(cr, uid, [('state','in',['manual','progress'])])
245- if sale_ids:
246- for sale_id in open_sale_ids:
247- sale_open_line_ids= sale_line_obj.search(cr,uid,[('order_id','=',sale_id),('product_id','=',product_id.id)])
248- for open_line_id in sale_open_line_ids:
249- sale_line_data= sale_line_obj.browse(cr,uid,open_line_id)
250- sale_qty += sale_line_data.product_uom_qty
251- ###################
252- purchase_ids = purchase_obj.search(cr,uid,[])
253- if purchase_ids:
254- start_pur_id = min(purchase_ids)
255- last_pur_id = max(purchase_ids)
256-
257- ##################calculation of date difference between first and last purchase order
258- first_purchase_date = purchase_obj.browse(cr,uid,start_pur_id).date_order
259- last_purchase_date = purchase_obj.browse(cr,uid,last_pur_id).date_order
260- first_date = time.mktime(time.strptime(first_purchase_date,'%Y-%m-%d'))
261- last_date = time.mktime(time.strptime(last_purchase_date,'%Y-%m-%d'))
262- pur_diff_day = (last_date-first_date)/(3600*24)
263- product_max_qty = 0.0
264- product_min_qty = 0.0
265-
266- if data['form']['method_qty_calculation'] == 'his_cons_with_product':
267- product_min_qty = int(math.ceil(average_daily_consumption * (supplier_lead_time + purchase_lead_time) * seasonal_factor))
268- product_max_qty = 2 * product_min_qty
269-
270- elif data['form']['method_qty_calculation'] == 'his_cons_without_product':
271- product_min_qty = int(math.ceil(plan_average_daily_consumption * (supplier_lead_time + purchase_lead_time) * seasonal_factor))
272- product_max_qty = 2 * product_min_qty
273-
274- else:
275- try:
276- product_min_qty = int(math.ceil((consum_qty + sale_qty) / pur_diff_day * (supplier_lead_time + purchase_lead_time) * seasonal_factor))
277- except Exception,e:
278- product_min_qty = 0.0
279- product_max_qty = 2 * product_min_qty
280-
281- if data['form']['delactive']:
282- stock_rule_ids = min_rule_obj.search(cr,uid,[('warehouse_id','=',data['form']['warehouse_id']),('product_id','=',product_id.id)])
283- for stock_rule_id in stock_rule_ids:
284- min_rule_obj.unlink(cr, uid, [stock_rule_id],context=context)
285-
286- mini_stock_rule_id = min_rule_obj.search(cr,uid,[('warehouse_id','=',data['form']['warehouse_id']),('product_id','=',product_id.id)])
287- if mini_stock_rule_id:
288- for stock_rule_id in mini_stock_rule_id:
289- min_rule_obj.write(cr, uid, [stock_rule_id],{'product_min_qty':product_min_qty,'product_max_qty':product_max_qty,},context=context)
290- else:
291- name = pool.get('ir.sequence').get(cr, uid, 'stock.orderpoint.calculator')
292- pool.get('stock.warehouse.orderpoint').create(cr, uid, {
293- 'name': name,
294- 'active': True,
295- 'warehouse_id': data['form']['warehouse_id'],
296- 'location_id': location_id,
297- 'product_id': id,
298- 'product_min_qty': product_min_qty,
299- 'product_max_qty': product_max_qty,
300- 'qty_multiple':1,
301- 'product_uom':product_id.uom_id.id,
302- 'logic':'max'
303- } )
304-
305-
306+
307+ # max_qty_factor factor
308+ max_qty_factor = data['form']['max_qty_factor']
309+
310+ # 1. Calculation of the date date start in one year later than current date
311+ from_date = (datetime.now() - relativedelta(months=12)).strftime('%Y-%m-%d %H:%M:%S')
312+ to_date = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
313+
314+ # 2.1 first find the all the product which fullfill the criteria of the 2.1
315+ product_ids = product_obj.search(cr,uid,[('active','=',True),('type','=','product'),
316+ ('procure_method','=','make_to_stock'),
317+ ('supply_method','=','buy'),
318+ ('purchase_ok','=',True),
319+ ('state','not in',['end','obsolete']),
320+ ])
321+ ####### get location #####
322+ location_id = data['form']['location_id']
323+ ###########
324+
325+ #2. Second point find the products for the perticular suppliers
326+ for partner_id in data['ids']:
327+ filter_products = []
328+ for product_id in product_ids:
329+ product_data = product_obj.browse(cr, uid, product_id, context=context)
330+ for seller_id in product_data.seller_ids:
331+ if seller_id.name.id == partner_id:
332+ filter_products.append(product_id)
333+
334+ #3. Calculation of the first stock input date as first input
335+ for filter_product_id in filter_products:
336+ product_data = pool.get('product.product').browse(cr, uid, filter_product_id, context=context)
337+ supplier_lead_time = 0.0
338+
339+ # supplier_lead_time of the supplier delay
340+ for seller_id in product_data.seller_ids:
341+ if seller_id.name.id == partner_id:
342+ supplier_lead_time = seller_id.delay
343+
344+ stock_move_ids = stock_move_obj.search(cr, uid, [('product_id','=',filter_product_id)])
345+
346+ average_daily_consumption = 0.0
347+ first_stock_move_ids = []
348+ # Take the first input date of the stock move where stock move of incoming picking or stock move not have any picking
349+ for first_stock_id in stock_move_ids:
350+ first_data = stock_move_obj.browse(cr, uid, first_stock_id, context=context)
351+ if first_data.picking_id:
352+ if first_data.picking_id.type == 'in':
353+ first_stock_move_ids.append(first_stock_id)
354+ else:
355+ first_stock_move_ids.append(first_stock_id)
356+
357+ if first_stock_move_ids:
358+ first_stock_move_id = first_stock_move_ids[0]
359+ first_input = stock_move_obj.browse(cr, uid, first_stock_move_id, context=context).date_planned
360+
361+ # Case 1 if first input is less than from date
362+ if first_input <= from_date:
363+ consum_qty = _sale_consume_qty(self, cr, uid, from_date, to_date, 'done', context)
364+ refund_qty = _refund_qty(self, cr, uid, filter_product_id, from_date, to_date, ['out_refund','in_refund'], context)
365+ open_sale_qty = _sale_open_qty(self, cr, uid, filter_product_id, from_date, to_date, ['manual','progress'], context)
366+ open_purchase_qty = _purchase_open_qty(self, cr, uid, filter_product_id, 'approved', context)
367+ pur_diff_day = _date_diff(self, cr, uid, filter_product_id, from_date, to_date, context)
368+ ### calculation of average_daily_consumption
369+ if pur_diff_day > 0:
370+ average_daily_consumption = (consum_qty - refund_qty + open_sale_qty - open_purchase_qty) / pur_diff_day
371+
372+ elif from_date < first_input and first_input < to_date:
373+ first_date = first_input
374+ consum_qty = _sale_consume_qty(self, cr, uid, filter_product_id, first_date, to_date, 'done', context)
375+ refund_qty = _refund_qty(self, cr, uid, filter_product_id, first_date, to_date, ['out_refund','in_refund'], context)
376+ open_sale_qty = _sale_open_qty(self, cr, uid, filter_product_id, ['manual','progress'], context)
377+ open_purchase_qty = _purchase_open_qty(self, cr, uid, filter_product_id, 'approved', context)
378+ pur_diff_day = _date_diff(self, cr, uid, filter_product_id, first_date, to_date, context)
379+
380+ ### calculation of average_daily_consumption
381+ if pur_diff_day>0:
382+ average_daily_consumption = (consum_qty - refund_qty + open_sale_qty - open_purchase_qty) / pur_diff_day
383+ else:
384+ open_sale_qty = _sale_open_qty(self, cr, uid, filter_product_id, ['manual','progress'], context)
385+ open_purchase_qty = _purchase_open_qty(self, cr, uid, filter_product_id, 'approved', context)
386+
387+ # calculation of first open purchase order date
388+ open_purchase_ids = purchase_obj.search(cr,uid,[('state','=','approved')])
389+ first_open_purchase_order = min(open_purchase_ids)
390+ fst_open_pur_date = purchase_obj.browse(cr, uid, first_open_purchase_order, context=context).date_order
391+
392+ # Days difference between to date and first purchase date
393+ pur_to_date = time.mktime(time.strptime(to_date,'%Y-%m-%d %H:%M:%S'))
394+ pur_open_date = time.mktime(time.strptime(fst_open_pur_date,'%Y-%m-%d'))
395+ pur_diff_day = (pur_to_date-pur_open_date)/(3600*24)
396+
397+ if pur_diff_day>0:
398+ average_daily_consumption = (open_sale_qty - open_purchase_qty)/pur_diff_day
399+
400+ ###### Calculation of plan_average_daily_consumption
401+ plan_average_daily_consumption = 0.0
402+ plan_average_daily_consumption = product_data.plan_avg_consume
403+
404+ if data['form']['method_qty_calculation'] == 'his_cons_with_product':
405+ product_min_qty = int(math.ceil(average_daily_consumption * (supplier_lead_time + purchase_lead_time) * seasonal_factor))
406+ product_max_qty = max_qty_factor * product_min_qty
407+
408+ elif data['form']['method_qty_calculation'] == 'his_cons_without_product':
409+ product_min_qty = int(math.ceil(plan_average_daily_consumption * (supplier_lead_time + purchase_lead_time) * seasonal_factor))
410+ product_max_qty = max_qty_factor * product_min_qty
411+
412+ else:
413+ try:
414+ product_min_qty = int(math.ceil((consum_qty + open_sale_qty) / pur_diff_day * (supplier_lead_time + purchase_lead_time) * seasonal_factor))
415+ except Exception,e:
416+ product_min_qty = 0.0
417+ product_max_qty = max_qty_factor * product_min_qty
418+
419+ if data['form']['delactive']:
420+ stock_rule_ids = min_rule_obj.search(cr,uid,[('warehouse_id','=',data['form']['warehouse_id']),('product_id','=',filter_product_id)])
421+ for stock_rule_id in stock_rule_ids:
422+ min_rule_obj.unlink(cr, uid, [stock_rule_id],context=context)
423+
424+ mini_stock_rule_id = min_rule_obj.search(cr,uid,[('warehouse_id','=',data['form']['warehouse_id']),('product_id','=',filter_product_id)])
425+ if mini_stock_rule_id:
426+ for stock_rule_id in mini_stock_rule_id:
427+ min_rule_obj.write(cr, uid, [stock_rule_id],{'product_min_qty':product_min_qty,'product_max_qty':product_max_qty,},context=context)
428+ else:
429+ name = pool.get('ir.sequence').get(cr, uid, 'stock.orderpoint.calculator')
430+ pool.get('stock.warehouse.orderpoint').create(cr, uid, {
431+ 'name': name,
432+ 'active': True,
433+ 'warehouse_id': data['form']['warehouse_id'],
434+ 'location_id': location_id,
435+ 'product_id': filter_product_id,
436+ 'product_min_qty': product_min_qty,
437+ 'product_max_qty': product_max_qty,
438+ 'qty_multiple':1,
439+ 'product_uom':product_data.uom_id.id,
440+ 'logic':'price',
441+ } )
442+
443 return {}
444
445 def _get_message(self, cr, uid, data, context):

Subscribers

People subscribed via source and target branches