[IMP] procurement: removed the schedule_range field on res.company which was error prone and not really usefull + made the scheduler run in SUPERUSER to avoid intercompany and access rights issues + made the run of procurement as SUPERUSER too for the same reasons

bzr revid: qdp-launchpad@openerp.com-20140403071010-5mrox75rkufur2nw
This commit is contained in:
Quentin (OpenERP) 2014-04-03 09:10:10 +02:00
parent 5b980f2b29
commit fe0e95d29b
9 changed files with 38 additions and 117 deletions

View File

@ -21,9 +21,9 @@
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from openerp.osv import fields from openerp.osv import osv, fields
from openerp.osv import osv
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp import SUPERUSER_ID
class procurement_rule(osv.osv): class procurement_rule(osv.osv):
_inherit = 'procurement.rule' _inherit = 'procurement.rule'
@ -75,7 +75,6 @@ class procurement_order(osv.osv):
company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
production_obj = self.pool.get('mrp.production') production_obj = self.pool.get('mrp.production')
bom_obj = self.pool.get('mrp.bom') bom_obj = self.pool.get('mrp.bom')
move_obj = self.pool.get('stock.move')
procurement_obj = self.pool.get('procurement.order') procurement_obj = self.pool.get('procurement.order')
for procurement in procurement_obj.browse(cr, uid, ids, context=context): for procurement in procurement_obj.browse(cr, uid, ids, context=context):
if self.check_bom_exists(cr, uid, [procurement.id], context=context): if self.check_bom_exists(cr, uid, [procurement.id], context=context):
@ -91,7 +90,8 @@ class procurement_order(osv.osv):
res_id = procurement.move_dest_id and procurement.move_dest_id.id or False res_id = procurement.move_dest_id and procurement.move_dest_id.id or False
newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.product_id.produce_delay or 0.0) newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.product_id.produce_delay or 0.0)
newdate = newdate - relativedelta(days=company.manufacturing_lead) newdate = newdate - relativedelta(days=company.manufacturing_lead)
produce_id = production_obj.create(cr, uid, { #create the MO as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
produce_id = production_obj.create(cr, SUPERUSER_ID, {
'origin': procurement.origin, 'origin': procurement.origin,
'product_id': procurement.product_id.id, 'product_id': procurement.product_id.id,
'product_qty': procurement.product_qty, 'product_qty': procurement.product_qty,

View File

@ -21,5 +21,4 @@
import procurement import procurement
import wizard import wizard
import company

View File

@ -49,7 +49,6 @@ depending on the product's configuration.
'procurement_data.xml', 'procurement_data.xml',
'wizard/schedulers_all_view.xml', 'wizard/schedulers_all_view.xml',
'procurement_view.xml', 'procurement_view.xml',
'company_view.xml',
], ],
'demo': [], 'demo': [],
'test': ['test/procurement.yml'], 'test': ['test/procurement.yml'],

View File

@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 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/>.
#
##############################################################################
from openerp.osv import osv,fields
class company(osv.osv):
_inherit = 'res.company'
_columns = {
'schedule_range': fields.float('Scheduler Range Days', required=True,
help="This is the time frame analysed by the scheduler when "\
"computing procurements. All procurements that are not between "\
"today and today+range are skipped for future computation."),
}
_defaults = {
'schedule_range': 730.0,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,20 +0,0 @@
<?xml version="1.0" ?>
<openerp>
<data>
<record id="mrp_company" model="ir.ui.view">
<field name="name">res.company.mrp.config</field>
<field name="model">res.company</field>
<field name="priority">17</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='account_grp']" position="after">
<group name="logistics_grp" string="Logistics">
<field name="schedule_range"/>
</group>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -21,9 +21,7 @@
import time import time
from datetime import datetime from openerp import SUPERUSER_ID
from dateutil.relativedelta import relativedelta
from openerp.osv import fields, osv from openerp.osv import fields, osv
import openerp.addons.decimal_precision as dp import openerp.addons.decimal_precision as dp
from openerp.tools.translate import _ from openerp.tools.translate import _
@ -31,7 +29,7 @@ import openerp
class procurement_group(osv.osv): class procurement_group(osv.osv):
''' '''
The procurement requirement class is used to group products together The procurement group class is used to group products together
when computing procurements. (tasks, physical products, ...) when computing procurements. (tasks, physical products, ...)
The goal is that when you have one sale order of several products The goal is that when you have one sale order of several products
@ -56,12 +54,11 @@ class procurement_group(osv.osv):
_description = 'Procurement Requisition' _description = 'Procurement Requisition'
_order = "id desc" _order = "id desc"
_columns = { _columns = {
'name': fields.char('Reference', required=True), 'name': fields.char('Reference', required=True),
'move_type': fields.selection([ 'move_type': fields.selection([
('direct', 'Partial'), ('one', 'All at once')], ('direct', 'Partial'), ('one', 'All at once')],
'Delivery Method', required=True), 'Delivery Method', required=True),
'partner_id': fields.many2one('res.partner', string = 'Partner'), #Sale should pass it here 'procurement_ids': fields.one2many('procurement.order', 'group_id', 'Procurements'),
'procurement_ids': fields.one2many('procurement.order', 'group_id', 'Procurements'),
} }
_defaults = { _defaults = {
'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').get(cr, uid, 'procurement.group') or '', 'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').get(cr, uid, 'procurement.group') or '',
@ -266,7 +263,8 @@ class procurement_order(osv.osv):
# #
def run_scheduler(self, cr, uid, use_new_cursor=False, context=None): def run_scheduler(self, cr, uid, use_new_cursor=False, context=None):
''' '''
Call the scheduler to check the procurement order Call the scheduler to check the procurement order. This is intented to be done for all existing companies at
the same time, so we're running all the methods as SUPERUSER to avoid intercompany and access rights issues.
@param self: The object pointer @param self: The object pointer
@param cr: The current row, from the database cursor, @param cr: The current row, from the database cursor,
@ -282,25 +280,22 @@ class procurement_order(osv.osv):
if use_new_cursor: if use_new_cursor:
cr = openerp.registry(use_new_cursor).db.cursor() cr = openerp.registry(use_new_cursor).db.cursor()
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
maxdate = (datetime.today() + relativedelta(days=company.schedule_range)).strftime('%Y-%m-%d %H:%M:%S')
# Run confirmed procurements # Run confirmed procurements
while True: while True:
ids = self.search(cr, uid, [('state', '=', 'confirmed'), ('date_planned', '<=', maxdate)], context=context) ids = self.search(cr, SUPERUSER_ID, [('state', '=', 'confirmed')], context=context)
if not ids: if not ids:
break break
self.run(cr, uid, ids, context=context) self.run(cr, SUPERUSER_ID, ids, context=context)
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
# Check if running procurements are done # Check if running procurements are done
offset = 0 offset = 0
while True: while True:
ids = self.search(cr, uid, [('state', '=', 'running'), ('date_planned', '<=', maxdate)], offset=offset, context=context) ids = self.search(cr, SUPERUSER_ID, [('state', '=', 'running')], offset=offset, context=context)
if not ids: if not ids:
break break
done = self.check(cr, uid, ids, context=context) done = self.check(cr, SUPERUSER_ID, ids, context=context)
offset += len(ids) - len(done) offset += len(ids) - len(done)
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()

View File

@ -1262,8 +1262,10 @@ class procurement_order(osv.osv):
} }
def make_po(self, cr, uid, ids, context=None): def make_po(self, cr, uid, ids, context=None):
""" Make purchase order from procurement """ Resolve the purchase from procurement, which may result in a new PO creation, a new PO line creation or a quantity change on existing PO line.
@return: New created Purchase Orders procurement wise Note that some operations (as the PO creation) are made as SUPERUSER because the current user may not have rights to do it (mto product launched by a sale for example)
@return: dictionary giving for each procurement its related resolving PO line.
""" """
res = {} res = {}
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
@ -1291,12 +1293,12 @@ class procurement_order(osv.osv):
available_po_line_ids = po_line_obj.search(cr, uid, [('order_id', '=', po_id), ('product_id', '=', line_vals['product_id']), ('product_uom', '=', line_vals['product_uom'])], context=context) available_po_line_ids = po_line_obj.search(cr, uid, [('order_id', '=', po_id), ('product_id', '=', line_vals['product_id']), ('product_uom', '=', line_vals['product_uom'])], context=context)
if available_po_line_ids: if available_po_line_ids:
po_line = po_line_obj.browse(cr, uid, available_po_line_ids[0], context=context) po_line = po_line_obj.browse(cr, uid, available_po_line_ids[0], context=context)
po_line_obj.write(cr, uid, po_line.id, {'product_qty': po_line.product_qty + line_vals['product_qty']}, context=context) po_line_obj.write(cr, SUPERUSER_ID, po_line.id, {'product_qty': po_line.product_qty + line_vals['product_qty']}, context=context)
po_line_id = po_line.id po_line_id = po_line.id
sum_po_line_ids.append(procurement.id) sum_po_line_ids.append(procurement.id)
else: else:
line_vals.update(order_id=po_id) line_vals.update(order_id=po_id)
po_line_id = po_line_obj.create(cr, uid, line_vals, context=context) po_line_id = po_line_obj.create(cr, SUPERUSER_ID, line_vals, context=context)
linked_po_ids.append(procurement.id) linked_po_ids.append(procurement.id)
else: else:
purchase_date = self._get_purchase_order_date(cr, uid, procurement, company, schedule_date, context=context) purchase_date = self._get_purchase_order_date(cr, uid, procurement, company, schedule_date, context=context)
@ -1314,7 +1316,7 @@ class procurement_order(osv.osv):
'payment_term_id': partner.property_supplier_payment_term.id or False, 'payment_term_id': partner.property_supplier_payment_term.id or False,
'dest_address_id': procurement.partner_dest_id.id, 'dest_address_id': procurement.partner_dest_id.id,
} }
po_id = self.create_procurement_purchase_order(cr, uid, procurement, po_vals, line_vals, context=context) po_id = self.create_procurement_purchase_order(cr, SUPERUSER_ID, procurement, po_vals, line_vals, context=context)
po_line_id = po_obj.browse(cr, uid, po_id, context=context).order_line[0].id po_line_id = po_obj.browse(cr, uid, po_id, context=context).order_line[0].id
pass_ids.append(procurement.id) pass_ids.append(procurement.id)
res[procurement.id] = po_line_id res[procurement.id] = po_line_id

View File

@ -176,12 +176,6 @@ class sale_order(osv.osv):
raise osv.except_osv( raise osv.except_osv(
_('Cannot cancel sales order!'), _('Cannot cancel sales order!'),
_('You must first cancel all delivery order(s) attached to this sales order.')) _('You must first cancel all delivery order(s) attached to this sales order.'))
# FP Note: not sure we need this
#if pick.state == 'cancel':
# for mov in pick.move_lines:
# proc_ids = proc_obj.search(cr, uid, [('move_id', '=', mov.id)])
# if proc_ids:
# proc_obj.signal_button_check(cr, uid, proc_ids)
stock_obj.signal_button_cancel(cr, uid, [p.id for p in sale.picking_ids]) stock_obj.signal_button_cancel(cr, uid, [p.id for p in sale.picking_ids])
return super(sale_order, self).action_cancel(cr, uid, ids, context=context) return super(sale_order, self).action_cancel(cr, uid, ids, context=context)

View File

@ -23,6 +23,7 @@ from openerp.osv import fields, osv
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from openerp import SUPERUSER_ID
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from datetime import datetime from datetime import datetime
import openerp import openerp
@ -216,7 +217,8 @@ class procurement_order(osv.osv):
return False return False
move_obj = self.pool.get('stock.move') move_obj = self.pool.get('stock.move')
move_dict = self._run_move_create(cr, uid, procurement, context=context) move_dict = self._run_move_create(cr, uid, procurement, context=context)
move_obj.create(cr, uid, move_dict, context=context) #create the move as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
move_obj.create(cr, SUPERUSER_ID, move_dict, context=context)
self.message_post(cr, uid, [procurement.id], body=_("Supply Move created"), context=context) self.message_post(cr, uid, [procurement.id], body=_("Supply Move created"), context=context)
return True return True
return super(procurement_order, self)._run(cr, uid, procurement, context=context) return super(procurement_order, self)._run(cr, uid, procurement, context=context)
@ -278,15 +280,11 @@ class procurement_order(osv.osv):
result['domain'] = "[('group_id','in',[" + ','.join(map(str, list(group_ids))) + "])]" result['domain'] = "[('group_id','in',[" + ','.join(map(str, list(group_ids))) + "])]"
return result return result
#
# Scheduler
# When stock is installed, it should also check for the different confirmed stock moves
# if they can not be installed
#
#
def run_scheduler(self, cr, uid, use_new_cursor=False, context=None): def run_scheduler(self, cr, uid, use_new_cursor=False, context=None):
''' '''
Call the scheduler in order to Call the scheduler in order to check the running procurements (super method), to check the minimum stock rules
and the availability of moves. This function is intended to be run for all the companies at the same time, so
we run functions as SUPERUSER to avoid intercompanies and access rights issues.
@param self: The object pointer @param self: The object pointer
@param cr: The current row, from the database cursor, @param cr: The current row, from the database cursor,
@ -296,7 +294,6 @@ class procurement_order(osv.osv):
@param context: A standard dictionary for contextual values @param context: A standard dictionary for contextual values
@return: Dictionary of values @return: Dictionary of values
''' '''
super(procurement_order, self).run_scheduler(cr, uid, use_new_cursor=use_new_cursor, context=context) super(procurement_order, self).run_scheduler(cr, uid, use_new_cursor=use_new_cursor, context=context)
if context is None: if context is None:
context = {} context = {}
@ -304,19 +301,19 @@ class procurement_order(osv.osv):
if use_new_cursor: if use_new_cursor:
cr = openerp.registry(use_new_cursor).db.cursor() cr = openerp.registry(use_new_cursor).db.cursor()
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
move_obj = self.pool.get('stock.move') move_obj = self.pool.get('stock.move')
#Minimum stock rules #Minimum stock rules
self. _procure_orderpoint_confirm(cr, uid, use_new_cursor=False, context=context, user_id=False) company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
self._procure_orderpoint_confirm(cr, SUPERUSER_ID, use_new_cursor=False, company_id=company.id, context=context)
#Search all confirmed stock_moves and try to assign them #Search all confirmed stock_moves and try to assign them
confirmed_ids = move_obj.search(cr, uid, [('state', '=', 'confirmed'), ('company_id','=', company.id)], limit=None, order='picking_priority desc, date_expected asc', context=context) confirmed_ids = move_obj.search(cr, uid, [('state', '=', 'confirmed')], limit=None, order='picking_priority desc, date_expected asc', context=context)
for x in xrange(0, len(confirmed_ids), 100): for x in xrange(0, len(confirmed_ids), 100):
move_obj.action_assign(cr, uid, confirmed_ids[x:x+100], context=context) move_obj.action_assign(cr, uid, confirmed_ids[x:x + 100], context=context)
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
finally: finally:
@ -327,7 +324,6 @@ class procurement_order(osv.osv):
pass pass
return {} return {}
def _get_orderpoint_date_planned(self, cr, uid, orderpoint, start_date, context=None): def _get_orderpoint_date_planned(self, cr, uid, orderpoint, start_date, context=None):
date_planned = start_date date_planned = start_date
return date_planned.strftime(DEFAULT_SERVER_DATE_FORMAT) return date_planned.strftime(DEFAULT_SERVER_DATE_FORMAT)
@ -349,17 +345,11 @@ class procurement_order(osv.osv):
[order_point.product_id.id], [order_point.product_id.id],
{'location': order_point.location_id.id})[order_point.product_id.id]['virtual_available'] {'location': order_point.location_id.id})[order_point.product_id.id]['virtual_available']
def _procure_orderpoint_confirm(self, cr, uid, \ def _procure_orderpoint_confirm(self, cr, uid, use_new_cursor=False, company_id=False, context=None):
use_new_cursor=False, context=None, user_id=False):
''' '''
Create procurement based on Orderpoint Create procurement based on Orderpoint
use_new_cursor: False or the dbname use_new_cursor: False or the dbname
@param self: The object pointer
@param cr: The current row, from the database cursor,
@param user_id: The current user ID for security checks
@param context: A standard dictionary for contextual values
@param param: False or the dbname
@return: Dictionary of values @return: Dictionary of values
""" """
''' '''
@ -368,18 +358,18 @@ class procurement_order(osv.osv):
if use_new_cursor: if use_new_cursor:
cr = openerp.registry(use_new_cursor).db.cursor() cr = openerp.registry(use_new_cursor).db.cursor()
orderpoint_obj = self.pool.get('stock.warehouse.orderpoint') orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')
procurement_obj = self.pool.get('procurement.order') procurement_obj = self.pool.get('procurement.order')
offset = 0 offset = 0
ids = [1] ids = [1]
while ids: while ids:
ids = orderpoint_obj.search(cr, uid, [], offset=offset, limit=100) ids = orderpoint_obj.search(cr, uid, [('company_id', '=', company_id)], offset=offset, limit=100)
for op in orderpoint_obj.browse(cr, uid, ids, context=context): for op in orderpoint_obj.browse(cr, uid, ids, context=context):
prods = self._product_virtual_get(cr, uid, op) prods = self._product_virtual_get(cr, uid, op)
if prods is None: if prods is None:
continue continue
if prods < op.product_min_qty: if prods < op.product_min_qty:
qty = max(op.product_min_qty, op.product_max_qty)-prods qty = max(op.product_min_qty, op.product_max_qty) - prods
reste = qty % op.qty_multiple reste = qty % op.qty_multiple
if reste > 0: if reste > 0:
@ -409,8 +399,7 @@ class procurement_order(osv.osv):
context=context) context=context)
self.check(cr, uid, [proc_id]) self.check(cr, uid, [proc_id])
self.run(cr, uid, [proc_id]) self.run(cr, uid, [proc_id])
orderpoint_obj.write(cr, uid, [op.id], orderpoint_obj.write(cr, uid, [op.id], {'procurement_id': proc_id}, context=context)
{'procurement_id': proc_id}, context=context)
offset += len(ids) offset += len(ids)
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()