[IMP] stock_planning: Separated osv_memory wizards into wizard folder.

bzr revid: uco@tinyerp.com-20100716051123-3yyrjsoyu0fgwqor
This commit is contained in:
uco 2010-07-16 10:41:23 +05:30
parent 02213dea5b
commit 6d5f567d18
11 changed files with 529 additions and 420 deletions

View File

@ -19,6 +19,7 @@
##############################################################################
import stock_planning
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -138,7 +138,13 @@ Remarks:
- When you wish to work with different periods for some part of products define two kinds of periods (fe. Weekly and Monthly) and use them for different products. Example: If you use always Weekly periods for Products A, and Monthly periods for Products B your all calculations will work correctly. You can also use different kind of periods for the same products from different warehouse or companies. But you cannot use overlapping periods for the same product, warehouse and company because results can be unpredictable. The same apply to Forecasts lines.
""",
"demo_xml":[],
"update_xml":["security/ir.model.access.csv","stock_planning_view.xml"],
"update_xml": [
"security/ir.model.access.csv",
"stock_planning_view.xml",
"wizard/stock_planning_create_periods_view.xml",
"wizard/stock_planning_forecast_view.xml",
"wizard/stock_planning_createlines_view.xml",
],
"active": False,
"installable": True,
}

View File

@ -35,88 +35,6 @@ def rounding(fl, round_value):
return fl
return round(fl / round_value) * round_value
# Object creating periods quickly
# changed that stop_date is created with hour 23:59:00 when it was 00:00:00 stop date was excluded from period
class stock_period_createlines(osv.osv_memory):
_name = "stock.period.createlines"
def _get_new_period_start(self, cr, uid, context=None):
cr.execute("select max(date_stop) from stock_period")
result = cr.fetchone()
last_date = result and result[0] or False
if last_date:
period_start = mx.DateTime.strptime(last_date,"%Y-%m-%d %H:%M:%S")+ RelativeDateTime(days=1)
period_start = period_start - RelativeDateTime(hours=period_start.hour, minutes=period_start.minute, seconds=period_start.second)
else:
period_start = mx.DateTime.today()
return period_start.strftime('%Y-%m-%d')
_columns = {
'name': fields.char('Period Name', size=64),
'date_start': fields.date('Start Date', required=True),
'date_stop': fields.date('End Date', required=True),
'period_ids': fields.one2many('stock.period', 'planning_id', 'Periods'),
}
_defaults={
'date_start': _get_new_period_start,
}
def create_period_weekly(self, cr, uid, ids, context=None):
res = self.create_period(cr, uid, ids, context=context)
return {
'view_type': 'form',
"view_mode": 'tree',
'res_model': 'stock.period',
'type': 'ir.actions.act_window',
}
def create_period_monthly(self, cr, uid, ids, context=None):
interval = context.get('interval',1)
for p in self.browse(cr, uid, ids, context=context):
dt = p.date_start
ds = mx.DateTime.strptime(p.date_start, '%Y-%m-%d')
while ds.strftime('%Y-%m-%d') < p.date_stop:
de = ds + RelativeDateTime(months=interval, minutes=-1)
self.pool.get('stock.period').create(cr, uid, {
'name': ds.strftime('%Y/%m'),
'date_start': ds.strftime('%Y-%m-%d'),
'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
})
ds = ds + RelativeDateTime(months=interval)
return {
'view_type': 'form',
"view_mode": 'tree',
'res_model': 'stock.period',
'type': 'ir.actions.act_window',
}
def create_period(self, cr, uid, ids, context=None):
interval = context.get('interval',0)
name = context.get('name','Daily')
for p in self.browse(cr, uid, ids, context=context):
dt = p.date_start
ds = mx.DateTime.strptime(p.date_start, '%Y-%m-%d')
while ds.strftime('%Y-%m-%d') < p.date_stop:
de = ds + RelativeDateTime(days=interval, minutes =-1)
if name =='Daily':
new_name=de.strftime('%Y-%m-%d')
if name =="Weekly":
new_name = de.strftime('%Y, week %W')
self.pool.get('stock.period').create(cr, uid, {
'name': new_name,
'date_start': ds.strftime('%Y-%m-%d'),
'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
})
ds = ds + RelativeDateTime(days=interval) + 1
return {
'view_type': 'form',
"view_mode": 'tree',
'res_model': 'stock.period',
'type': 'ir.actions.act_window',
}
stock_period_createlines()
# Periods have no company_id field as they can be shared across similar companies.
# If somone thinks different it can be improved.
class stock_period(osv.osv):
@ -134,104 +52,6 @@ class stock_period(osv.osv):
stock_period()
# Creates forecasts records for products from selected Product Category for selected 'Warehouse - Period'
# Object added by contributor in ver 1.1
class stock_sale_forecast_createlines(osv.osv_memory):
_name = "stock.sale.forecast.createlines"
_description = "stock.sale.forecast.createlines"
# FIXME Add some period sugestion like below
# def _get_latest_period(self,cr,uid,context={}):
# cr.execute("select max(date_stop) from stock_period")
# result=cr.fetchone()
# return result and result[0] or False
_columns = {
'company_id': fields.many2one('res.company', 'Company', required=True, select=1),
'warehouse_id1': fields.many2one('stock.warehouse' , 'Warehouse', required=True, \
help='Warehouse which forecasts will concern. '\
'If during stock planning you will need sales forecast for all warehouses choose any warehouse now.'),
'period_id1': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which forecasts will concern.' ),
'product_categ_id1': fields.many2one('product.category' , 'Product Category', required=True, \
help ='Product Category of products which created forecasts will concern.'),
'copy_forecast': fields.boolean('Copy Last Forecast', help="Copy quantities from last Stock and Sale Forecast."),
}
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.sale.forecast.createlines', context=c),
}
def create_forecast(self, cr, uid, ids, context=None):
product_obj = self.pool.get('product.product')
forecast_obj = self.pool.get('stock.sale.forecast')
mod_obj = self.pool.get('ir.model.data')
prod_categ_obj = self.pool.get('product.category')
template_obj = self.pool.get('product.template')
for f in self.browse(cr, uid, ids, context=context):
categ_ids = f.product_categ_id1.id and [f.product_categ_id1.id] or []
prod_categ_ids = prod_categ_obj.search(cr, uid, [('parent_id','child_of', categ_ids)])
templates_ids = template_obj.search(cr, uid, [('categ_id','in',prod_categ_ids)])
products_ids = product_obj.search(cr, uid, [('product_tmpl_id','in',templates_ids)])
if len(products_ids) == 0:
raise osv.except_osv(_('Error !'), _('No products in selected category !'))
copy = f.copy_forecast
for p in product_obj.browse(cr, uid, products_ids,{}):
if len(forecast_obj.search(cr, uid, [('product_id','=',p.id) , \
('period_id','=',f.period_id1.id), \
('user_id','=',uid), \
('warehouse_id','=',f.warehouse_id1.id)]))== 0:
forecast_qty = 0.0
# Not sure if it is expected quantity for this feature (copying forecast from previous period)
# because it can take incidental forecast of this warehouse, this product and this user (creating, writing or validating forecast).
# It takes only one forecast line (no sum). If user creates only one forecast per period it will be OK. If not I have no idea how to count it.
prod_uom = False
if copy:
cr.execute("SELECT period.date_stop, forecast.product_qty, forecast.product_uom \
FROM stock_sale_forecast AS forecast \
LEFT JOIN stock_period AS period \
ON forecast.period_id = period.id \
WHERE (forecast.user_id = %s OR forecast.create_uid = %s OR forecast.write_uid = %s) \
AND forecast.warehouse_id = %s AND forecast.product_id = %s \
AND period.date_stop < %s \
ORDER BY period.date_stop DESC",
(uid, uid, uid, f.warehouse_id1.id, p.id, f.period_id1.date_stop) )
ret = cr.fetchone()
if ret:
forecast_qty = ret[1]
prod_uom = ret[2]
prod_uom = prod_uom or p.uom_id.id
prod_uos_categ = False
if p.uos_id:
prod_uos_categ = p.uos_id.category_id.id
forecast_obj.create(cr, uid, {
'company_id': f.warehouse_id1.company_id.id,
'period_id': f.period_id1.id,
'warehouse_id': f.warehouse_id1.id,
'product_id': p.id,
'product_qty': forecast_qty,
'product_amt': 0.0,
'product_uom': prod_uom,
'active_uom': prod_uom,
'product_uom_categ': p.uom_id.category_id.id,
'product_uos_categ': prod_uos_categ,
})
result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_sale_forecast_filter')
id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
return {
'view_type': 'form',
"view_mode": 'tree',
'res_model': 'stock.sale.forecast',
'type': 'ir.actions.act_window',
'search_view_id': id['res_id'],
}
stock_sale_forecast_createlines()
# Stock and Sales Forecast object. Previously stock_planning_sale_prevision.
# A lot of changes in 1.1
class stock_sale_forecast(osv.osv):
@ -477,124 +297,6 @@ class stock_sale_forecast(osv.osv):
stock_sale_forecast()
# Creates stock planning records for products from selected Product Category for selected 'Warehouse - Period'
# Object added by contributor in ver 1.1
class stock_planning_createlines(osv.osv_memory):
_name = "stock.planning.createlines"
def onchange_company(self, cr, uid, ids, company_id=False):
result = {}
if company_id:
result['warehouse_id2'] = False
return {'value': result}
_columns = {
'company_id': fields.many2one('res.company', 'Company', required=True),
'period_id2': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which planning will concern.'),
'warehouse_id2': fields.many2one('stock.warehouse' , 'Warehouse', required=True, help = 'Warehouse which planning will concern.'),
'product_categ_id2': fields.many2one('product.category' , 'Product Category', \
help = 'Planning will be created for products from Product Category selected by this field. '\
'This field is ignored when you check \"All Forecasted Product\" box.' ),
'forecasted_products': fields.boolean('All Products with Forecast', \
help = "Check this box to create planning for all products having any forecast for selected Warehouse and Period. "\
"Product Category field will be ignored."),
}
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.planning', context=c),
}
def create_planning(self,cr, uid, ids, context=None):
if context is None:
context = {}
product_obj = self.pool.get('product.product')
planning_obj = self.pool.get('stock.planning')
mod_obj = self.pool.get('ir.model.data')
for f in self.browse(cr, uid, ids, context=context):
if f.forecasted_products:
cr.execute("SELECT product_id \
FROM stock_sale_forecast \
WHERE (period_id = %s) AND (warehouse_id = %s)", (f.period_id2.id, f.warehouse_id2.id))
products_id1 = [x for x, in cr.fetchall()]
else:
prod_categ_obj = self.pool.get('product.category')
template_obj = self.pool.get('product.template')
categ_ids = f.product_categ_id2.id and [f.product_categ_id2.id] or []
prod_categ_ids = prod_categ_obj.search(cr,uid,[('parent_id','child_of',categ_ids)])
templates_ids = template_obj.search(cr,uid,[('categ_id','in',prod_categ_ids)])
products_id1 = product_obj.search(cr,uid,[('product_tmpl_id','in',templates_ids)])
if len(products_id1)==0:
raise osv.except_osv(_('Error !'), _('No forecasts for selected period or no products in selected category !'))
for p in product_obj.browse(cr, uid, products_id1,context=context):
if len(planning_obj.search(cr, uid, [('product_id','=',p.id),
('period_id','=',f.period_id2.id),
('warehouse_id','=',f.warehouse_id2.id)]))== 0:
cr.execute("SELECT period.date_stop, planning.product_uom, planning.planned_outgoing, planning.to_procure, \
planning.stock_only, planning.procure_to_stock, planning.confirmed_forecasts_only, \
planning.supply_warehouse_id, planning.stock_supply_location \
FROM stock_planning AS planning \
LEFT JOIN stock_period AS period \
ON planning.period_id = period.id \
WHERE (planning.create_uid = %s OR planning.write_uid = %s) \
AND planning.warehouse_id = %s AND planning.product_id = %s \
AND period.date_stop < %s \
ORDER BY period.date_stop DESC",
(uid, uid, f.warehouse_id2.id, p.id, f.period_id2.date_stop) )
ret=cr.fetchone()
# forecast_qty = ret and ret[0] or 0.0
if ret:
# raise osv.except_osv(_('Error !'), _('ret is %s %s %s %s %s %s')%(ret[0],ret[2],ret[3],ret[4],ret[5],ret[6],))
prod_uom = ret[1]
planned_out = ret[2]
to_procure = ret[3]
stock_only = ret[4]
procure_to_stock = ret[5]
confirmed_forecasts_only = ret[6]
supply_warehouse_id = ret[7]
stock_supply_location = ret[8]
else:
prod_uom = p.uom_id.id
planned_out = False
to_procure = False
stock_only = False
procure_to_stock = False
confirmed_forecasts_only = False
supply_warehouse_id = False
stock_supply_location = False
prod_uos_categ = False
if p.uos_id:
prod_uos_categ = p.uos_id.category_id.id
planning_obj.create(cr, uid, {
'company_id' : f.warehouse_id2.company_id.id,
'period_id': f.period_id2.id,
'warehouse_id' : f.warehouse_id2.id,
'product_id': p.id,
'product_uom' : prod_uom,
'product_uom_categ' : p.uom_id.category_id.id,
'product_uos_categ' : prod_uos_categ,
'active_uom' : prod_uom,
'planned_outgoing': planned_out,
'to_procure': to_procure,
'stock_only': stock_only,
'procure_to_stock': procure_to_stock,
'confirmed_forecasts_only': confirmed_forecasts_only,
'supply_warehouse_id': supply_warehouse_id,
'stock_supply_location': stock_supply_location,
})
result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_planning_filter')
id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
return {
'view_type': 'form',
"view_mode": 'tree',
'res_model': 'stock.planning',
'type': 'ir.actions.act_window',
'search_view_id': id['res_id'],
}
stock_planning_createlines()
# The main Stock Planning object
# A lot of changes by contributor in ver 1.1
class stock_planning(osv.osv):

View File

@ -5,42 +5,6 @@
name="Stock and Sales Periods"
parent="base.menu_base_config" sequence="20"/>
<!-- Creating periods section -->
<record id="view_stock_period_createlines_form" model="ir.ui.view">
<field name="name">stock.period.createlines.form</field>
<field name="model">stock.period.createlines</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Stock and Sales Periods">
<separator colspan="4" string="Create periods for Stock and Sales Planning"/>
<field name="date_start"/>
<field name="date_stop"/>
<separator colspan="4" string=""/>
<group col="3" colspan="4">
<button name="create_period" icon="gtk-execute" string="Create Daily Periods" type="object"/>
<button name="create_period_weekly" icon="gtk-execute" string="Create Weekly Periods" type="object" context="{'interval': 6, 'name': 'Weekly'}"/>
<button name="create_period_monthly" icon="gtk-execute" string="Create Monthly Periods" type="object" context="{'interval': 1}"/>
</group>
</form>
</field>
</record>
<record id="action_stock_period_createlines_form" model="ir.actions.act_window">
<field name="name">Stock and Sales Planning Periods</field>
<field name="res_model">stock.period.createlines</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_stock_period_createlines_form"/>
<field name="target">new</field>
</record>
<menuitem id="menu_stock_period_creatlines"
name="Create Stock and Sales Periods"
parent="menu_stock_period_main"
action="action_stock_period_createlines_form"
sequence = "5"/>
<!-- Periods tree and form section -->
<record id="view_stock_period_form" model="ir.ui.view">
@ -85,46 +49,6 @@
action="action_stock_period_form"
sequence = "10"/>
<!-- Create Forecast section -->
<record id="view_stock_sale_forecast_createlines_form" model="ir.ui.view">
<field name="name">stock.sale.forecast.createlines</field>
<field name="model">stock.sale.forecast.createlines</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Stock and Sales Forecasts">
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<newline/>
<field name="period_id1"/>
<newline/>
<field name="warehouse_id1" domain = "[('company_id','=',company_id)] "/>
<newline/>
<field name="product_categ_id1" widget="selection"/>
<newline/>
<field name="copy_forecast"/>
<separator colspan ="4" string="Forecast lines creation"/>
<label colspan ="4" string="Creates forecast lines for selected warehouse and period. Doesn't duplicate existing lines created by you."/>
<group colspan="4">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-execute" name="create_forecast" string="Create Forecasts" type="object" />
</group>
</form>
</field>
</record>
<record id="action_stock_sale_forecast_createlines_form" model="ir.actions.act_window">
<field name="name">Create Sales Forecasts</field>
<field name="res_model">stock.sale.forecast.createlines</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_stock_sale_forecast_createlines_form"/>
<field name="target">new</field>
</record>
<menuitem id="menu_stock_sale_forecast" name="Sales Forecasts"
parent="base.menu_base_partner" sequence="6"/>
<menuitem id="menu_stock_sale_forecast_createlines" name="Create Sales Forecasts" parent="menu_stock_sale_forecast" action="action_stock_sale_forecast_createlines_form" sequence = "5"/>
<record id="view_stock_sale_forecast_form" model="ir.ui.view">
<field name="name">stock.sale.forecast.form</field>
<field name="model">stock.sale.forecast</field>
@ -232,9 +156,13 @@
</graph>
</field>
</record>
<!-- Forecast section -->
<menuitem id="menu_stock_sale_forecast" name="Sales Forecasts"
parent="base.menu_base_partner" sequence="6"/>
<record id="view_stock_sale_forecast_filter" model="ir.ui.view">
<record id="view_stock_sale_forecast_filter" model="ir.ui.view">
<field name="name">stock.sale.forecast.list.select</field>
<field name="model">stock.sale.forecast</field>
<field name="type">search</field>
@ -273,50 +201,9 @@
parent="menu_stock_sale_forecast"
action="action_view_stock_sale_forecast_form"/>
<!-- Create Planning section -->
<menuitem id="menu_stock_planning_main" name="Stock Planning" parent="stock.menu_stock_root" sequence="2"/>
<record id="view_stock_planning_createlines_form" model="ir.ui.view">
<field name="name">stock.planning.createlines.form</field>
<field name="model">stock.planning.createlines</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Stock Planning">
<field name="company_id" widget= "selection" on_change="onchange_company(company_id)" groups="base.group_multi_company"/>
<newline/>
<field name="period_id2" widget="selection"/>
<newline/>
<field name="warehouse_id2" domain = "[('company_id','=',company_id)] "/>
<newline/>
<field name="forecasted_products"/>
<newline/>
<field name="product_categ_id2" attrs="{'required':[('forecasted_products','=',0)]}" widget="selection"/>
<separator colspan ="4" string="Stock planning lines creation"/>
<label colspan ="4" string="Creates planning lines for selected period and warehouse. Doesn't duplicate existing lines created by you."/>
<group colspan="4">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-ok" name="create_planning" string="Create Stock Planning" type="object"/>
</group>
</form>
</field>
</record>
<record id="action_stock_planning_createlines_form" model="ir.actions.act_window">
<field name="name">Create Stock Planning Lines</field>
<field name="res_model">stock.planning.createlines</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_stock_planning_createlines_form"/>
<field name="target">new</field>
</record>
<menuitem
id="menu_stock_planning_createlines"
parent="menu_stock_planning_main"
action="action_stock_planning_createlines_form" sequence = "5"/>
<!-- Planning section -->
<menuitem id="menu_stock_planning_main" name="Stock Planning" parent="stock.menu_stock_root" sequence="2"/>
<record id="view_stock_planning_form" model="ir.ui.view">
<field name="name">stock.planning.form</field>

View File

@ -0,0 +1,23 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import stock_planning_create_periods
import stock_planning_forecast
import stock_planning_createlines

View File

@ -0,0 +1,90 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
import mx.DateTime
from mx.DateTime import RelativeDateTime, now, DateTime, localtime
from osv import osv, fields
# Object creating periods quickly
# changed that stop_date is created with hour 23:59:00 when it was 00:00:00 stop date was excluded from period
class stock_period_createlines(osv.osv_memory):
_name = "stock.period.createlines"
def _get_new_period_start(self, cr, uid, context=None):
cr.execute("select max(date_stop) from stock_period")
result = cr.fetchone()
last_date = result and result[0] or False
if last_date:
period_start = mx.DateTime.strptime(last_date,"%Y-%m-%d %H:%M:%S")+ RelativeDateTime(days=1)
period_start = period_start - RelativeDateTime(hours=period_start.hour, minutes=period_start.minute, seconds=period_start.second)
else:
period_start = mx.DateTime.today()
return period_start.strftime('%Y-%m-%d')
_columns = {
'name': fields.char('Period Name', size=64),
'date_start': fields.date('Start Date', required=True),
'date_stop': fields.date('End Date', required=True),
'period_ids': fields.one2many('stock.period', 'planning_id', 'Periods'),
}
_defaults={
'date_start': _get_new_period_start,
}
def create_stock_periods(self, cr, uid, ids, context=None):
interval = context.get('interval',0)
name = context.get('name','Daily')
period_obj = self.pool.get('stock.period')
lines = []
for p in self.browse(cr, uid, ids, context=context):
dt = p.date_start
ds = mx.DateTime.strptime(p.date_start, '%Y-%m-%d')
while ds.strftime('%Y-%m-%d') < p.date_stop:
if name =='Daily':
de = ds + RelativeDateTime(days=interval, minutes =-1)
new_name = de.strftime('%Y-%m-%d')
ds = ds + RelativeDateTime(days=interval) + 1
if name =="Weekly":
de = ds + RelativeDateTime(days=interval, minutes =-1)
new_name = de.strftime('%Y, week %W')
ds = ds + RelativeDateTime(days=interval) + 1
if name == "Monthly":
de = ds + RelativeDateTime(months=interval, minutes=-1)
new_name = ds.strftime('%Y/%m')
ds = ds + RelativeDateTime(months=interval)
lines.append(period_obj.create(cr, uid, {
'name': new_name,
'date_start': ds.strftime('%Y-%m-%d'),
'date_stop': de.strftime('%Y-%m-%d %H:%M:%S'),
}))
return {
'domain': "[('id','in', ["+','.join(map(str, lines))+"])]",
'view_type': 'form',
"view_mode": 'tree, form',
'res_model': 'stock.period',
'type': 'ir.actions.act_window',
}
stock_period_createlines()

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Creating periods section -->
<record id="view_stock_period_createlines_form" model="ir.ui.view">
<field name="name">stock.period.createlines.form</field>
<field name="model">stock.period.createlines</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Stock and Sales Periods">
<separator colspan="4" string="Create periods for Stock and Sales Planning"/>
<field name="date_start"/>
<field name="date_stop"/>
<separator colspan="4" string=""/>
<group col="3" colspan="4">
<button name="create_stock_periods" icon="gtk-execute" string="Create Daily Periods" type="object"/>
<button name="create_stock_periods" icon="gtk-execute" string="Create Weekly Periods" type="object" context="{'interval': 6, 'name': 'Weekly'}"/>
<button name="create_stock_periods" icon="gtk-execute" string="Create Monthly Periods" type="object" context="{'interval': 1, 'name': 'Monthly'}"/>
</group>
</form>
</field>
</record>
<record id="action_stock_period_createlines_form" model="ir.actions.act_window">
<field name="name">Stock and Sales Planning Periods</field>
<field name="res_model">stock.period.createlines</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_stock_period_createlines_form"/>
<field name="target">new</field>
</record>
<menuitem id="menu_stock_period_creatlines"
name="Create Stock and Sales Periods"
parent="menu_stock_period_main"
action="action_stock_period_createlines_form"
sequence = "5"/>
</data>
</openerp>

View File

@ -0,0 +1,145 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
from tools.translate import _
# Creates stock planning records for products from selected Product Category for selected 'Warehouse - Period'
# Object added by contributor in ver 1.1
class stock_planning_createlines(osv.osv_memory):
_name = "stock.planning.createlines"
def onchange_company(self, cr, uid, ids, company_id=False):
result = {}
if company_id:
result['warehouse_id2'] = False
return {'value': result}
_columns = {
'company_id': fields.many2one('res.company', 'Company', required=True),
'period_id2': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which planning will concern.'),
'warehouse_id2': fields.many2one('stock.warehouse' , 'Warehouse', required=True, help = 'Warehouse which planning will concern.'),
'product_categ_id2': fields.many2one('product.category' , 'Product Category', \
help = 'Planning will be created for products from Product Category selected by this field. '\
'This field is ignored when you check \"All Forecasted Product\" box.' ),
'forecasted_products': fields.boolean('All Products with Forecast', \
help = "Check this box to create planning for all products having any forecast for selected Warehouse and Period. "\
"Product Category field will be ignored."),
}
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.planning', context=c),
}
def create_planning(self,cr, uid, ids, context=None):
if context is None:
context = {}
product_obj = self.pool.get('product.product')
planning_obj = self.pool.get('stock.planning')
mod_obj = self.pool.get('ir.model.data')
prod_categ_obj = self.pool.get('product.category')
template_obj = self.pool.get('product.template')
planning_lines = []
for f in self.browse(cr, uid, ids, context=context):
if f.forecasted_products:
cr.execute("SELECT product_id \
FROM stock_sale_forecast \
WHERE (period_id = %s) AND (warehouse_id = %s)", (f.period_id2.id, f.warehouse_id2.id))
products_id1 = [x for x, in cr.fetchall()]
else:
categ_ids = f.product_categ_id2.id and [f.product_categ_id2.id] or []
prod_categ_ids = prod_categ_obj.search(cr,uid,[('parent_id','child_of',categ_ids)])
templates_ids = template_obj.search(cr,uid,[('categ_id','in',prod_categ_ids)])
products_id1 = product_obj.search(cr,uid,[('product_tmpl_id','in',templates_ids)])
if len(products_id1)==0:
raise osv.except_osv(_('Error !'), _('No forecasts for selected period or no products in selected category !'))
for p in product_obj.browse(cr, uid, products_id1,context=context):
if len(planning_obj.search(cr, uid, [('product_id','=',p.id),
('period_id','=',f.period_id2.id),
('warehouse_id','=',f.warehouse_id2.id)]))== 0:
cr.execute("SELECT period.date_stop, planning.product_uom, planning.planned_outgoing, planning.to_procure, \
planning.stock_only, planning.procure_to_stock, planning.confirmed_forecasts_only, \
planning.supply_warehouse_id, planning.stock_supply_location \
FROM stock_planning AS planning \
LEFT JOIN stock_period AS period \
ON planning.period_id = period.id \
WHERE (planning.create_uid = %s OR planning.write_uid = %s) \
AND planning.warehouse_id = %s AND planning.product_id = %s \
AND period.date_stop < %s \
ORDER BY period.date_stop DESC",
(uid, uid, f.warehouse_id2.id, p.id, f.period_id2.date_stop) )
ret=cr.fetchone()
# forecast_qty = ret and ret[0] or 0.0
if ret:
# raise osv.except_osv(_('Error !'), _('ret is %s %s %s %s %s %s')%(ret[0],ret[2],ret[3],ret[4],ret[5],ret[6],))
prod_uom = ret[1]
planned_out = ret[2]
to_procure = ret[3]
stock_only = ret[4]
procure_to_stock = ret[5]
confirmed_forecasts_only = ret[6]
supply_warehouse_id = ret[7]
stock_supply_location = ret[8]
else:
prod_uom = p.uom_id.id
planned_out = False
to_procure = False
stock_only = False
procure_to_stock = False
confirmed_forecasts_only = False
supply_warehouse_id = False
stock_supply_location = False
prod_uos_categ = False
if p.uos_id:
prod_uos_categ = p.uos_id.category_id.id
planning_lines.append(planning_obj.create(cr, uid, {
'company_id' : f.warehouse_id2.company_id.id,
'period_id': f.period_id2.id,
'warehouse_id' : f.warehouse_id2.id,
'product_id': p.id,
'product_uom' : prod_uom,
'product_uom_categ' : p.uom_id.category_id.id,
'product_uos_categ' : prod_uos_categ,
'active_uom' : prod_uom,
'planned_outgoing': planned_out,
'to_procure': to_procure,
'stock_only': stock_only,
'procure_to_stock': procure_to_stock,
'confirmed_forecasts_only': confirmed_forecasts_only,
'supply_warehouse_id': supply_warehouse_id,
'stock_supply_location': stock_supply_location,
}))
result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_planning_filter')
id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
return {
'domain': "[('id','in', ["+','.join(map(str, planning_lines))+"])]",
'view_type': 'form',
"view_mode": 'tree',
'res_model': 'stock.planning',
'type': 'ir.actions.act_window',
'search_view_id': id['res_id'],
}
stock_planning_createlines()

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Create Planning section -->
<record id="view_stock_planning_createlines_form" model="ir.ui.view">
<field name="name">stock.planning.createlines.form</field>
<field name="model">stock.planning.createlines</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Stock Planning">
<field name="company_id" widget= "selection" on_change="onchange_company(company_id)" groups="base.group_multi_company"/>
<newline/>
<field name="period_id2" widget="selection"/>
<newline/>
<field name="warehouse_id2" domain = "[('company_id','=',company_id)] "/>
<newline/>
<field name="forecasted_products"/>
<newline/>
<field name="product_categ_id2" attrs="{'required':[('forecasted_products','=',0)]}" widget="selection"/>
<separator colspan ="4" string="Stock planning lines creation"/>
<label colspan ="4" string="Creates planning lines for selected period and warehouse. Doesn't duplicate existing lines created by you."/>
<group colspan="4">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-ok" name="create_planning" string="Create Stock Planning" type="object"/>
</group>
</form>
</field>
</record>
<record id="action_stock_planning_createlines_form" model="ir.actions.act_window">
<field name="name">Create Stock Planning Lines</field>
<field name="res_model">stock.planning.createlines</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_stock_planning_createlines_form"/>
<field name="target">new</field>
</record>
<menuitem
id="menu_stock_planning_createlines"
parent="menu_stock_planning_main"
action="action_stock_planning_createlines_form" sequence = "5"/>
</data>
</openerp>

View File

@ -0,0 +1,122 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
# Creates forecasts records for products from selected Product Category for selected 'Warehouse - Period'
# Object added by contributor in ver 1.1
class stock_sale_forecast_createlines(osv.osv_memory):
_name = "stock.sale.forecast.createlines"
_description = "stock.sale.forecast.createlines"
# FIXME Add some period sugestion like below
# def _get_latest_period(self,cr,uid,context={}):
# cr.execute("select max(date_stop) from stock_period")
# result=cr.fetchone()
# return result and result[0] or False
_columns = {
'company_id': fields.many2one('res.company', 'Company', required=True, select=1),
'warehouse_id1': fields.many2one('stock.warehouse' , 'Warehouse', required=True, \
help='Warehouse which forecasts will concern. '\
'If during stock planning you will need sales forecast for all warehouses choose any warehouse now.'),
'period_id1': fields.many2one('stock.period' , 'Period', required=True, help = 'Period which forecasts will concern.' ),
'product_categ_id1': fields.many2one('product.category' , 'Product Category', required=True, \
help ='Product Category of products which created forecasts will concern.'),
'copy_forecast': fields.boolean('Copy Last Forecast', help="Copy quantities from last Stock and Sale Forecast."),
}
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.sale.forecast.createlines', context=c),
}
def create_forecast(self, cr, uid, ids, context=None):
product_obj = self.pool.get('product.product')
forecast_obj = self.pool.get('stock.sale.forecast')
mod_obj = self.pool.get('ir.model.data')
prod_categ_obj = self.pool.get('product.category')
template_obj = self.pool.get('product.template')
forecast_lines = []
for f in self.browse(cr, uid, ids, context=context):
categ_ids = f.product_categ_id1.id and [f.product_categ_id1.id] or []
prod_categ_ids = prod_categ_obj.search(cr, uid, [('parent_id','child_of', categ_ids)])
templates_ids = template_obj.search(cr, uid, [('categ_id','in',prod_categ_ids)])
products_ids = product_obj.search(cr, uid, [('product_tmpl_id','in',templates_ids)])
if len(products_ids) == 0:
raise osv.except_osv(_('Error !'), _('No products in selected category !'))
copy = f.copy_forecast
for p in product_obj.browse(cr, uid, products_ids,{}):
if len(forecast_obj.search(cr, uid, [('product_id','=',p.id) , \
('period_id','=',f.period_id1.id), \
('user_id','=',uid), \
('warehouse_id','=',f.warehouse_id1.id)]))== 0:
forecast_qty = 0.0
# Not sure if it is expected quantity for this feature (copying forecast from previous period)
# because it can take incidental forecast of this warehouse, this product and this user (creating, writing or validating forecast).
# It takes only one forecast line (no sum). If user creates only one forecast per period it will be OK. If not I have no idea how to count it.
prod_uom = False
if copy:
cr.execute("SELECT period.date_stop, forecast.product_qty, forecast.product_uom \
FROM stock_sale_forecast AS forecast \
LEFT JOIN stock_period AS period \
ON forecast.period_id = period.id \
WHERE (forecast.user_id = %s OR forecast.create_uid = %s OR forecast.write_uid = %s) \
AND forecast.warehouse_id = %s AND forecast.product_id = %s \
AND period.date_stop < %s \
ORDER BY period.date_stop DESC",
(uid, uid, uid, f.warehouse_id1.id, p.id, f.period_id1.date_stop) )
ret = cr.fetchone()
if ret:
forecast_qty = ret[1]
prod_uom = ret[2]
prod_uom = prod_uom or p.uom_id.id
prod_uos_categ = False
if p.uos_id:
prod_uos_categ = p.uos_id.category_id.id
forecast_lines.append(forecast_obj.create(cr, uid, {
'company_id': f.warehouse_id1.company_id.id,
'period_id': f.period_id1.id,
'warehouse_id': f.warehouse_id1.id,
'product_id': p.id,
'product_qty': forecast_qty,
'product_amt': 0.0,
'product_uom': prod_uom,
'active_uom': prod_uom,
'product_uom_categ': p.uom_id.category_id.id,
'product_uos_categ': prod_uos_categ,
}))
result = mod_obj._get_id(cr, uid, 'stock_planning', 'view_stock_sale_forecast_filter')
id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
return {
'domain': "[('id','in', ["+','.join(map(str, forecast_lines))+"])]",
'view_type': 'form',
"view_mode": 'tree',
'res_model': 'stock.sale.forecast',
'type': 'ir.actions.act_window',
'search_view_id': id['res_id'],
}
stock_sale_forecast_createlines()

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Create Forecast section -->
<record id="view_stock_sale_forecast_createlines_form" model="ir.ui.view">
<field name="name">stock.sale.forecast.createlines</field>
<field name="model">stock.sale.forecast.createlines</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Stock and Sales Forecasts">
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<newline/>
<field name="period_id1"/>
<newline/>
<field name="warehouse_id1" domain = "[('company_id','=',company_id)] "/>
<newline/>
<field name="product_categ_id1" widget="selection"/>
<newline/>
<field name="copy_forecast"/>
<separator colspan ="4" string="Forecast lines creation"/>
<label colspan ="4" string="Creates forecast lines for selected warehouse and period. Doesn't duplicate existing lines created by you."/>
<group colspan="4">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-execute" name="create_forecast" string="Create Forecasts" type="object" />
</group>
</form>
</field>
</record>
<record id="action_stock_sale_forecast_createlines_form" model="ir.actions.act_window">
<field name="name">Create Sales Forecasts</field>
<field name="res_model">stock.sale.forecast.createlines</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_stock_sale_forecast_createlines_form"/>
<field name="target">new</field>
</record>
<menuitem id="menu_stock_sale_forecast_createlines" name="Create Sales Forecasts"
parent="menu_stock_sale_forecast" action="action_stock_sale_forecast_createlines_form" sequence="5"/>
</data>
</openerp>