From ba69c9f7d691ee25e6293db8362ec10beb553d5e Mon Sep 17 00:00:00 2001 From: "grzegorz.grzelak@cirrus.pl" <> Date: Fri, 21 Jan 2011 10:13:05 +0100 Subject: [PATCH 001/803] [REF] modification for new 6.0 lookout bzr revid: grzegorz.grzelak@cirrus.pl-20110121091305-a4cq8oahe3k8xks7 --- addons/stock_planning/__openerp__.py | 34 ++++----- addons/stock_planning/stock_planning.py | 73 +++++++++++++------ addons/stock_planning/stock_planning_view.xml | 20 +++-- .../stock_planning_create_periods_view.xml | 8 +- .../stock_planning_createlines_view.xml | 21 ++++-- .../wizard/stock_planning_forecast_view.xml | 1 + 6 files changed, 99 insertions(+), 58 deletions(-) diff --git a/addons/stock_planning/__openerp__.py b/addons/stock_planning/__openerp__.py index d0566424cca..cf36d5db0fd 100644 --- a/addons/stock_planning/__openerp__.py +++ b/addons/stock_planning/__openerp__.py @@ -22,17 +22,17 @@ { "name":"Master Procurement Schedule", "version":"1.1", - "author":"OpenERP SA and Grzegorz Grzelak (Cirrus)", - "category":"Custom", - "depends":["hr","stock","sale"], + "author":"OpenERP SA and Grzegorz Grzelak (OpenGLOBE)", + "category":"Stock", + "depends":["hr","stock","sale","procurement"], "description": """ This module is based on original OpenERP SA module stock_planning version 1.0 of the same name Master Procurement Schedule. Purpose of MPS is to allow create a manual procurement (requisition) apart of MRP scheduler (which works automatically on minimum stock rules). Terms used in the module: -- Stock and Sales Period - is the time (between Start Date and End Date) for which you plan Stock and Sales Forecast and make Procurement Planning. -- Stock and Sales Forecast - is the quantity of products you plan to sell in the Period. +- Stock Period - is the time (between Start Date and End Date) for which you plan Stock and Sales Forecast and make Procurement Planning. +- Sales Forecast - is the quantity of products you plan to sell in the Period. - Stock Planning - is the quantity of products you plan to purchase or produce for the Period. Because we have another module sale_forecast which uses terms "Sales Forecast" and "Planning" as amount values we will use terms "Stock and Sales Forecast" and "Stock Planning" to emphasize that we use quantity values. @@ -44,14 +44,14 @@ Activity with this module is divided to three steps: Periods ======= -You have two menu items for Periods in "Sales Management - Configuration". There are: -- "Create Sales Periods" - Which automates creating daily, weekly or monthly periods. -- "Stock and sales Periods" - Which allows to create any type of periods, change the dates and change the State of period. +You have two menu items for Periods in "Warehouse - Configuration - Stock Periods". There are: +- "Create Stock Periods" - Which automates creating daily, weekly or monthly periods. +- "Stock Periods" - Which allows to create any type of periods, change the dates and change the State of period. -Creating periods is the first step you have to do to use modules features. You can create custom periods using "New" button in "Stock and Sales Periods" form or view but it is recommended to use automating tool. +Creating periods is the first step you have to do to use modules features. You can create custom periods using "New" button in "Stock Periods" form or view but it is recommended to use automating tool "Create Stock Periods". Remarks: -- These periods (officially Stock and Sales Periods) are separated of Financial or other periods in the system. +- These periods (Stock Periods) are separated of Financial or other periods in the system. - Periods are not assigned to companies (when you use multicompany feature at all). Module suppose that you use the same periods across companies. If you wish to use different periods for different companies define them as you wish (they can overlap). Later on in this text will be indications how to use such periods. - When periods are created automatically their start and finish dates are with start hour 00:00:00 and end hour 23:59:00. Fe. when you create daily periods they will have start date 31.01.2010 00:00:00 and end date 31.01.2010 23:59:00. It works only in automatic creation of periods. When you create periods manually you have to take care about hours because you can have incorrect values form sales or stock. - If you use overlapping periods for the same product, warehouse and company results can be unpredictable. @@ -59,11 +59,11 @@ Remarks: Sales Forecasts =============== -You have few menus for Sales forecast in "Sales Management - Sales Forecasts". -- "Create Sales Forecasts for Sales Periods" - which automates creating forecasts lines according to some parameters. +You have few menus for Sales forecast in "Sales - Sales Forecasts". +- "Create Sales Forecasts" - which automates creating forecasts lines according to some parameters. - "Sales Forecasts" - few menus for working with forecasts lists and forms. -Menu "Create Sales Forecasts for Sales Periods" creates Forecasts for products from selected Category, for selected Period and for selected Warehouse. It is an option "Copy Last Forecast" to copy forecast and other settings of period before this one to created one. +Menu "Create Sales Forecasts" creates Forecasts for products from selected Category, for selected Period and for selected Warehouse. It is an option "Copy Last Forecast" to copy forecast and other settings of period before this one to created one. Remarks: - This tool doesn't create lines, if relevant lines (for the same Product, Period, Warehouse and validated or created by you) already exists. If you wish to create another forecast, if relevant lines exists you have to do it manually using menus described bellow. @@ -71,21 +71,21 @@ Remarks: - When you choose "Copy Last Forecast" created line takes quantity and some settings from your (validated by you or created by you if not validated yet) forecast which is for last period before period of created forecast. If there are few your forecasts for period before this one (it is possible) system takes one of them (no rule which of them). -Menus "Sales Forecasts" +Menu "Sales Forecasts" On "Sales Forecast" form mainly you have to enter a forecast quantity in "Product Quantity". Further calculation can work for draft forecasts. But validation can save your data against any accidental changes. You can click "Validate" button but it is not mandatory. Instead of forecast quantity you can enter amount of forecast sales in field "Product Amount". System will count quantity from amount according to Sale price of the Product. -All values on the form are expressed in unit of measure selected on form. You can select one of unit of measure from default category or from second category. When you change unit of measure the quanities will be recalculated according to new UoM: editable values (blue fields) immediately, non edited fields after clicking of "Calculate Planning" button. +All values on the form are expressed in unit of measure selected on form. You can select one of unit of measure from default category or from second category. When you change unit of measure the quanities will be recalculated according to new UoM: editable values (blue fields) immediately, non edited fields after clicking of "Calculate Sales History" button. To find proper value for Sale Forecast you can use "Sales History" table for this product. You have to enter parameters to the top and left of this table and system will count sale quantities according to these parameters. So you can select fe. your department (at the top) then (to the left): last period, period before last and period year ago. Remarks: - +- Developers can consider to replace sales history "per Department" with "per Sales Team" as Sales Team was introduced in 6.0. Procurement Planning ==================== -Menu for Planning you can find in "Warehouse - Stock Planning". +Menu for Planning you can find in "Warehouse - Manual Planning". - "Create Stock Planning Lines" - allows you to automate creating planning lines according to some parameters. - "Master Procurement Scheduler" - is the most important menu of the module which allows to create procurement. diff --git a/addons/stock_planning/stock_planning.py b/addons/stock_planning/stock_planning.py index 9fdd94c909d..94da7b027a1 100644 --- a/addons/stock_planning/stock_planning.py +++ b/addons/stock_planning/stock_planning.py @@ -26,6 +26,8 @@ from dateutil.relativedelta import relativedelta from osv import osv, fields import netsvc from tools.translate import _ +import logging + def rounding(fl, round_value): if not round_value: @@ -76,15 +78,15 @@ class stock_sale_forecast(osv.osv): 'product_id': fields.many2one('product.product', 'Product', readonly=True, required=True, states={'draft':[('readonly',False)]}, \ help = 'Shows which product this forecast concerns.'), 'product_qty': fields.float('Product Quantity', required=True, readonly=True, states={'draft':[('readonly',False)]}, \ - help= 'Forecasted quantity.'), + help= 'Forecast quantity.'), 'product_amt': fields.float('Product Amount', readonly=True, states={'draft':[('readonly',False)]}, \ help='Forecast value which will be converted to Product Quantity according to prices.'), 'product_uom_categ': fields.many2one('product.uom.categ', 'Product UoM Category'), # Invisible field for product_uom domain 'product_uom': fields.many2one('product.uom', 'Product UoM', required=True, readonly=True, states={'draft':[('readonly',False)]}, \ - help = "Unit of Measure used to show the quanities of stock calculation." \ + help = "Unit of Measure used to show the quantities of stock calculation." \ "You can use units form default category or from second category (UoS category)."), 'product_uos_categ' : fields.many2one('product.uom.categ', 'Product UoS Category'), # Invisible field for product_uos domain -# Field used in onchange_uom to check what uom was before change and recalculate quantities acording to old uom (active_uom) and new uom. +# Field used in onchange_uom to check what uom was before change and recalculate quantities according to old uom (active_uom) and new uom. 'active_uom': fields.many2one('product.uom', string = "Active UoM"), 'state': fields.selection([('draft','Draft'),('validated','Validated')],'State',readonly=True), 'analyzed_period1_id': fields.many2one('stock.period', 'Period1', readonly=True, states={'draft':[('readonly',False)]},), @@ -114,7 +116,7 @@ class stock_sale_forecast(osv.osv): 'analyzed_period3_per_warehouse': fields.float('This Warehouse Period3', readonly=True), 'analyzed_period4_per_warehouse': fields.float('This Warehouse Period4', readonly=True), 'analyzed_period5_per_warehouse': fields.float('This Warehouse Period5', readonly=True), - 'analyzed_period1_per_company': fields.float('This Copmany Period1', readonly=True), + 'analyzed_period1_per_company': fields.float('This Company Period1', readonly=True), 'analyzed_period2_per_company': fields.float('This Company Period2', readonly=True), 'analyzed_period3_per_company': fields.float('This Company Period3', readonly=True), 'analyzed_period4_per_company': fields.float('This Company Period4', readonly=True), @@ -196,7 +198,7 @@ class stock_sale_forecast(osv.osv): uom = uom_obj.browse(cr, uid, uom_id, context=context) coef = uom.factor if uom.category_id.id <> product.uom_id.category_id.id: - coef = coef / product.uos_coeff + coef = coef * product.uos_coeff return product.uom_id.factor / coef def _from_default_uom_factor(self, cr, uid, product_id, uom_id, context=None): @@ -206,7 +208,7 @@ class stock_sale_forecast(osv.osv): uom = uom_obj.browse(cr, uid, uom_id, context=context) res = uom.factor if uom.category_id.id <> product.uom_id.category_id.id: - res = res / product.uos_coeff + res = res * product.uos_coeff return res / product.uom_id.factor, uom.rounding def _sales_per_users(self, cr, uid, so, so_line, company, users): @@ -343,18 +345,41 @@ class stock_planning(osv.osv): GROUP BY planning.product_uom", \ (date_start, date_stop, val.product_id.id, val.company_id.id,)) planning_qtys = cr.fetchall() - res = self._to_planning_uom(cr, uid, val, planning_qtys, context) + res = self._to_default_uom(cr, uid, val, planning_qtys, context) return res - def _to_planning_uom(self, cr, uid, val, qtys, context=None): + def _to_default_uom(self, cr, uid, val, qtys, context=None): + res_qty = 0 + if qtys: + uom_obj = self.pool.get('product.uom') + for qty, prod_uom in qtys: + coef = self._to_default_uom_factor(cr, uid, val.product_id.id, prod_uom, context=context) +# res_coef, round_value = self._from_default_uom_factor(cr, uid, val.product_id.id, val.product_uom.id, context=context) +# logging.getLogger().info(str(coef)+" "+str(qty)+" "+str(res_qty)) +# print coef +# print res_coef +# raise osv.except_osv(_('Error !'), _('coef and res_coef %s %s')%(coef,res_coef,)) +# coef = coef * res_coef +# res_qty += rounding(qty * coef, round_value) + res_qty += qty * coef +# logging.getLogger().info(str(coef)+" "+str(qty)+" "+str(res_qty)) + return res_qty + + def _to_form_uom(self, cr, uid, val, qtys, context=None): res_qty = 0 if qtys: uom_obj = self.pool.get('product.uom') for qty, prod_uom in qtys: coef = self._to_default_uom_factor(cr, uid, val.product_id.id, prod_uom, context=context) res_coef, round_value = self._from_default_uom_factor(cr, uid, val.product_id.id, val.product_uom.id, context=context) +# logging.getLogger().info(str(coef)+" "+str(qty)+" "+str(res_qty)) +# print coef +# print res_coef +# raise osv.except_osv(_('Error !'), _('coef and res_coef %s %s')%(coef,res_coef,)) coef = coef * res_coef res_qty += rounding(qty * coef, round_value) +# res_qty += qty * coef +# logging.getLogger().info(str(coef)+" "+str(qty)+" "+str(res_qty)) return res_qty @@ -369,7 +394,7 @@ class stock_planning(osv.osv): 'GROUP BY product_uom', \ (val.product_id.id,val.period_id.id, val.company_id.id)) company_qtys = cr.fetchall() - res[val.id]['company_forecast'] = self._to_planning_uom(cr, uid, val, company_qtys, context) + res[val.id]['company_forecast'] = self._to_form_uom(cr, uid, val, company_qtys, context) cr.execute('SELECT sum(product_qty), product_uom \ FROM stock_sale_forecast \ @@ -377,8 +402,8 @@ class stock_planning(osv.osv): 'GROUP BY product_uom', \ (val.product_id.id,val.period_id.id, val.warehouse_id.id)) warehouse_qtys = cr.fetchall() - res[val.id]['warehouse_forecast'] = self._to_planning_uom(cr, uid, val, warehouse_qtys, context) - res[val.id]['warehouse_forecast'] = rounding(res[val.id]['warehouse_forecast'], val.product_id.uom_id.rounding) + res[val.id]['warehouse_forecast'] = self._to_form_uom(cr, uid, val, warehouse_qtys, context) +# res[val.id]['warehouse_forecast'] = rounding(res[val.id]['warehouse_forecast'], val.product_id.uom_id.rounding) return res def _get_stock_start(self, cr, uid, val, date, context=None): @@ -419,7 +444,7 @@ class stock_planning(osv.osv): res_coef, round_value = self._from_default_uom_factor(cr, uid, val.product_id.id, val.product_uom.id, context=context) coef = coef * res_coef res[val.id]['minimum_op'] = rounding(ret[0]*coef, round_value) - res[val.id]['maximum_op'] = ret[1]*coef + res[val.id]['maximum_op'] = rounding(ret[1]*coef, round_value) return res def onchange_company(self, cr, uid, ids, company_id=False): @@ -451,11 +476,11 @@ class stock_planning(osv.osv): 'warehouse_id': fields.many2one('stock.warehouse','Warehouse', required=True), 'product_id': fields.many2one('product.product' , 'Product', required=True, help = 'Product which this planning is created for.'), 'product_uom_categ' : fields.many2one('product.uom.categ', 'Product UoM Category'), # Invisible field for product_uom domain - 'product_uom': fields.many2one('product.uom', 'UoM', required=True, help = "Unit of Measure used to show the quanities of stock calculation." \ - "You can use units form default category or from second category (UoS category)."), + 'product_uom': fields.many2one('product.uom', 'UoM', required=True, help = "Unit of Measure used to show the quantities of stock calculation." \ + "You can use units from default category or from second category (UoS category)."), 'product_uos_categ': fields.many2one('product.uom.categ', 'Product UoM Category'), # Invisible field for product_uos domain -# Field used in onchange_uom to check what uom was before change to recalculate quantities acording to old uom (active_uom) and new uom. - 'active_uom': fields.many2one('product.uom', string = "Active UoM"), +# Field used in onchange_uom to check what uom was before change to recalculate quantities according to old uom (active_uom) and new uom. + 'active_uom': fields.many2one('product.uom', string = "Active UoM"), # It works only in Forecast 'planned_outgoing': fields.float('Planned Out', required=True, \ help = 'Enter planned outgoing quantity from selected Warehouse during the selected Period of selected Product. '\ 'To plan this value look at Confirmed Out or Sales Forecasts. This value should be equal or greater than Confirmed Out.'), @@ -475,16 +500,16 @@ class stock_planning(osv.osv): help = 'Quantity left to Planned incoming quantity. This is calculated difference between Planned In and Confirmed In. ' \ 'For current period Already In is also calculated. This value is used to create procurement for lacking quantity.'), 'outgoing_left': fields.float('Expected Out', readonly=True, \ - help = 'Quantity expected to go out in selected period. As a difference between Planned Out and Confirmed Out. ' \ + help = 'Quantity expected to go out in selected period besides Confirmed Out. As a difference between Planned Out and Confirmed Out. ' \ 'For current period Already Out is also calculated'), 'to_procure': fields.float(string='Planned In', required=True, \ help = 'Enter quantity which (by your plan) should come in. Change this value and observe Stock simulation. ' \ 'This value should be equal or greater than Confirmed In.'), 'line_time': fields.function(_get_past_future, method=True,type='char', string='Past/Future'), 'minimum_op': fields.function(_get_op, method=True, type='float', string = 'Minimum Rule', multi= 'minimum', \ - help = 'Minimum quantity set in Minimum Stock Rules for this Warhouse'), + help = 'Minimum quantity set in Minimum Stock Rules for this Warehouse'), 'maximum_op': fields.function(_get_op, method=True, type='float', string = 'Maximum Rule', multi= 'maximum', \ - help = 'Maximum quantity set in Minimum Stock Rules for this Warhouse'), + help = 'Maximum quantity set in Minimum Stock Rules for this Warehouse'), 'outgoing_before': fields.float('Planned Out Before', readonly=True, \ help= 'Planned Out in periods before calculated. '\ 'Between start date of current period and one day before start of calculated period.'), @@ -499,13 +524,13 @@ class stock_planning(osv.osv): help= 'Quantity which is already picked up to this warehouse in current period.'), 'stock_only': fields.boolean("Stock Location Only", help = "Check to calculate stock location of selected warehouse only. " \ "If not selected calculation is made for input, stock and output location of warehouse."), - "procure_to_stock": fields.boolean("Procure To Stock Location", help = "Chect to make procurement to stock location of selected warehouse. " \ + "procure_to_stock": fields.boolean("Procure To Stock Location", help = "Check to make procurement to stock location of selected warehouse. " \ "If not selected procurement will be made into input location of warehouse."), "confirmed_forecasts_only": fields.boolean("Validated Forecasts", help = "Check to take validated forecasts only. " \ "If not checked system takes validated and draft forecasts."), - 'supply_warehouse_id': fields.many2one('stock.warehouse','Source Warehouse', help = "Warehouse used as source in supply pick move created by 'Supply from Another Warhouse'."), + 'supply_warehouse_id': fields.many2one('stock.warehouse','Source Warehouse', help = "Warehouse used as source in supply pick move created by 'Supply from Another Warehouse'."), "stock_supply_location": fields.boolean("Stock Supply Location", help = "Check to supply from Stock location of Supply Warehouse. " \ - "If not checked supply will be made from Output location of Supply Warehouse. Used in 'Supply from Another Warhouse' with Supply Warehouse."), + "If not checked supply will be made from Output location of Supply Warehouse. Used in 'Supply from Another Warehouse' with Supply Warehouse."), } @@ -525,7 +550,7 @@ class stock_planning(osv.osv): uom = uom_obj.browse(cr, uid, uom_id, context=context) coef = uom.factor if uom.category_id.id != product.uom_id.category_id.id: - coef = coef / product.uos_coeff + coef = coef * product.uos_coeff return product.uom_id.factor / coef @@ -536,7 +561,7 @@ class stock_planning(osv.osv): uom = uom_obj.browse(cr, uid, uom_id, context=context) res = uom.factor if uom.category_id.id != product.uom_id.category_id.id: - res = res / product.uos_coeff + res = res * product.uos_coeff return res / product.uom_id.factor, uom.rounding def calculate_planning(self, cr, uid, ids, context, *args): diff --git a/addons/stock_planning/stock_planning_view.xml b/addons/stock_planning/stock_planning_view.xml index 9995752cb03..d7b6d312500 100644 --- a/addons/stock_planning/stock_planning_view.xml +++ b/addons/stock_planning/stock_planning_view.xml @@ -2,8 +2,8 @@ + name="Stock Periods" + parent="stock.menu_stock_configuration" sequence="20"/> @@ -12,7 +12,7 @@ stock.period form -
+ @@ -46,7 +46,7 @@ stock.period search - + @@ -58,11 +58,13 @@ - Stock and Sales Periods + Stock Periods stock.period form tree,form + Stock periods are used for stock planning. Stock periods are independent of account periods. You can use wizard for creating periods and review them here. + tree,form,graph {"search_default_create_uid":uid} + This quantity sales forecast is an indication for Stock Planner to make procurement manually or to complement automatic procurement. You can use manual procurement with this forecast when some periods are exceptional for usual minimum stock rules. - + stock.planning.form @@ -247,6 +250,7 @@ + @@ -339,11 +343,13 @@ form tree,form + Manual planning can be used as basic planning in the company or can complement automatic planning (schedulers). On planning form you can see quantities of stock at the beginning of current period, sum of outgoing moves, sum of incoming moves and simulation of stock at the end of period. Changing values of Planned In and Planned Out you can simulate other situation. When you are satisfied with value of Stock Simulation you can manually procure additional quantity of Incoming Left. + diff --git a/addons/stock_planning/wizard/stock_planning_create_periods_view.xml b/addons/stock_planning/wizard/stock_planning_create_periods_view.xml index 35b55b8f4e7..bb18769fdfd 100644 --- a/addons/stock_planning/wizard/stock_planning_create_periods_view.xml +++ b/addons/stock_planning/wizard/stock_planning_create_periods_view.xml @@ -8,8 +8,7 @@ stock.period.createlines form - - + @@ -24,16 +23,17 @@ - Stock and Sales Planning Periods + Stock Periods stock.period.createlines form form + This wizard simplify creating periods used for stock planning. These periods are independent of account periods. If you wish to create periods other than day, week or month you have to create them manually in Stock Periods. new diff --git a/addons/stock_planning/wizard/stock_planning_createlines_view.xml b/addons/stock_planning/wizard/stock_planning_createlines_view.xml index 7dc4504daef..3b26e6446f8 100644 --- a/addons/stock_planning/wizard/stock_planning_createlines_view.xml +++ b/addons/stock_planning/wizard/stock_planning_createlines_view.xml @@ -10,15 +10,11 @@ form - + - - -