from datetime import datetime
from dateutil.relativedelta import relativedelta
-from openerp.osv import fields
-from openerp.osv import osv
+from openerp.osv import osv, fields
from openerp.tools.translate import _
+from openerp import SUPERUSER_ID
class procurement_rule(osv.osv):
_inherit = 'procurement.rule'
company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
production_obj = self.pool.get('mrp.production')
bom_obj = self.pool.get('mrp.bom')
- move_obj = self.pool.get('stock.move')
procurement_obj = self.pool.get('procurement.order')
for procurement in procurement_obj.browse(cr, uid, ids, context=context):
if self.check_bom_exists(cr, uid, [procurement.id], context=context):
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 = 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,
'product_id': procurement.product_id.id,
'product_qty': procurement.product_qty,
import procurement
import wizard
-import company
'procurement_data.xml',
'wizard/schedulers_all_view.xml',
'procurement_view.xml',
- 'company_view.xml',
],
'demo': [],
'test': ['test/procurement.yml'],
+++ /dev/null
-# -*- 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:
+++ /dev/null
-<?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>
import time
-from datetime import datetime
-from dateutil.relativedelta import relativedelta
-
+from openerp import SUPERUSER_ID
from openerp.osv import fields, osv
import openerp.addons.decimal_precision as dp
from openerp.tools.translate import _
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, ...)
The goal is that when you have one sale order of several products
_description = 'Procurement Requisition'
_order = "id desc"
_columns = {
- 'name': fields.char('Reference', required=True),
+ 'name': fields.char('Reference', required=True),
'move_type': fields.selection([
('direct', 'Partial'), ('one', 'All at once')],
'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 = {
'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').get(cr, uid, 'procurement.group') or '',
#
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 cr: The current row, from the database cursor,
if use_new_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
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:
break
- self.run(cr, uid, ids, context=context)
+ self.run(cr, SUPERUSER_ID, ids, context=context)
if use_new_cursor:
cr.commit()
# Check if running procurements are done
offset = 0
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:
break
- done = self.check(cr, uid, ids, context=context)
+ done = self.check(cr, SUPERUSER_ID, ids, context=context)
offset += len(ids) - len(done)
if use_new_cursor:
cr.commit()
}
def make_po(self, cr, uid, ids, context=None):
- """ Make purchase order from procurement
- @return: New created Purchase Orders procurement wise
+ """ 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.
+ 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 = {}
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
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:
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
sum_po_line_ids.append(procurement.id)
else:
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)
else:
purchase_date = self._get_purchase_order_date(cr, uid, procurement, company, schedule_date, context=context)
'payment_term_id': partner.property_supplier_payment_term.id or False,
'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
pass_ids.append(procurement.id)
res[procurement.id] = po_line_id
raise osv.except_osv(
_('Cannot cancel 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])
return super(sale_order, self).action_cancel(cr, uid, ids, context=context)
from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
+from openerp import SUPERUSER_ID
from dateutil.relativedelta import relativedelta
from datetime import datetime
import openerp
return False
move_obj = self.pool.get('stock.move')
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)
return True
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
result['domain'] = "[('group_id','in',[" + ','.join(map(str, list(group_ids))) + "])]"
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):
'''
- 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 cr: The current row, from the database cursor,
@param context: A standard dictionary for contextual values
@return: Dictionary of values
'''
-
super(procurement_order, self).run_scheduler(cr, uid, use_new_cursor=use_new_cursor, context=context)
if context is None:
context = {}
if use_new_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')
+
#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
- 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):
- 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:
cr.commit()
-
-
+
if use_new_cursor:
cr.commit()
finally:
pass
return {}
-
def _get_orderpoint_date_planned(self, cr, uid, orderpoint, start_date, context=None):
date_planned = start_date
return date_planned.strftime(DEFAULT_SERVER_DATE_FORMAT)
[order_point.product_id.id],
{'location': order_point.location_id.id})[order_point.product_id.id]['virtual_available']
- def _procure_orderpoint_confirm(self, cr, uid, \
- use_new_cursor=False, context=None, user_id=False):
+ def _procure_orderpoint_confirm(self, cr, uid, use_new_cursor=False, company_id=False, context=None):
'''
Create procurement based on Orderpoint
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
"""
'''
if use_new_cursor:
cr = openerp.registry(use_new_cursor).db.cursor()
orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')
-
+
procurement_obj = self.pool.get('procurement.order')
offset = 0
ids = [1]
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):
prods = self._product_virtual_get(cr, uid, op)
if prods is None:
continue
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
if reste > 0:
context=context)
self.check(cr, uid, [proc_id])
self.run(cr, uid, [proc_id])
- orderpoint_obj.write(cr, uid, [op.id],
- {'procurement_id': proc_id}, context=context)
+ orderpoint_obj.write(cr, uid, [op.id], {'procurement_id': proc_id}, context=context)
offset += len(ids)
if use_new_cursor:
cr.commit()