stock.move.group renamed to procurement.group

procurement module (where stock.move.group was defined) does not depend on the stock module
the same grouping system could be used for services too

procurement.group
removed sequence_id field
put a default values on the name field, using a defined sequence
renamed "Move Group" into "Procurement Requisition"

procurement object:
location_id should not come from the customer property but should be stored on the procurement (set by the sale order, using the customer property)

bzr revid: fp@tinyerp.com-20130629091328-5gc39647aa2pymlf
This commit is contained in:
Fabien Pinckaers 2013-06-29 11:13:28 +02:00
parent 7bbcdf7621
commit 471dd0998d
8 changed files with 57 additions and 129 deletions

View File

@ -65,7 +65,7 @@ class StockMove(osv.osv):
_inherit = 'stock.move'
_columns= {
'procurements': fields.one2many('procurement.order', 'move_id', 'Procurements'),
'group_id':fields.many2one('stock.move.group', 'Move Group'),
'group_id':fields.many2one('procurement.group', 'Move Group'),
}
def copy_data(self, cr, uid, id, default=None, context=None):
@ -75,25 +75,38 @@ class StockMove(osv.osv):
return super(StockMove, self).copy_data(cr, uid, id, default, context=context)
class move_group(osv.osv):
class procurement_group(osv.osv):
'''
The procurement requirement class is used to group procurement orders.
The goal is that when you have one delivery order of several products
and the products are pulled from the same or several location(s), to keep having
the moves grouped into pickings.
As the pulled moves are created by the procurement orders who are created by moves/SO/...,
the procurement requisition will bundle these procurement orders according to the same original picking
Suppose you have 4 lines on a picking from Output where 2 lines will need to come from Input and 2 lines coming from Stock -> Output
As the four procurement orders will have the same group ids from the SO, the move from input will have a stock.picking with 2 grouped lines
and the move from stock will have 2 grouped lines also.
The procurement requirement 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
and the products are pulled from the same or several location(s), to keep
having the moves grouped into pickings that represent the sale order.
Used in: sales order (to group delivery order lines like the so), pull/push
rules (to pack like the delivery order), on orderpoints (e.g. for wave picking
all the similar products together).
Grouping is made only if the source and the destination is the same.
Suppose you have 4 lines on a picking from Output where 2 lines will need
to come from Input (crossdock) and 2 lines coming from Stock -> Output As
the four procurement orders will have the same group ids from the SO, the
move from input will have a stock.picking with 2 grouped lines and the move
from stock will have 2 grouped lines also.
The name is usually the name of the original document (sale order) or a
sequence computed if created manually.
'''
_name = 'stock.move.group'
_name = 'procurement.group'
_description = 'Procurement Requisition'
_order = "id desc"
_columns = {
'name': fields.char('Name'),
'sequence_id': fields.many2one('ir.sequence', 'Group Sequence', help="Move group sequence"),
}
'name': fields.char('Reference'),
}
_defaults = {
'name': lambda self,cr,uid,c: self.pool.get('ir.sequence').get(cr,uid,'procurement.group') or ''
}
@ -140,7 +153,7 @@ class procurement_order(osv.osv):
\nAfter confirming the status is set to \'Running\'.\n If any exception arises in the order then the status is set to \'Exception\'.\n Once the exception is removed the status becomes \'Ready\'.\n It is in \'Waiting\'. status when the procurement is waiting for another one to finish.'),
'note': fields.text('Note'),
'company_id': fields.many2one('res.company','Company',required=True),
'group_id':fields.many2one('stock.move.group', 'Move Group'),
'group_id':fields.many2one('procurement.group', 'Procurement Requisition'),
}
_defaults = {
'state': 'draft',
@ -329,8 +342,6 @@ class procurement_order(osv.osv):
@return: True
"""
move_obj = self.pool.get('stock.move')
mod_obj = self.pool.get('ir.model.data')
location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', 'stock_location_customers')
for procurement in self.browse(cr, uid, ids, context=context):
if procurement.product_qty <= 0.00:
raise osv.except_osv(_('Data Insufficient!'),
@ -338,7 +349,7 @@ class procurement_order(osv.osv):
if procurement.product_id.type in ('product', 'consu'):
if not procurement.move_id:
source = procurement.location_id.id
if procurement.procure_method == 'make_to_order':#and source != location_id: Last statement is not good
if procurement.procure_method == 'make_to_order':
source = procurement.product_id.property_stock_procurement.id
id = move_obj.create(cr, uid, {
'name': procurement.name,
@ -354,8 +365,7 @@ class procurement_order(osv.osv):
})
move_obj.action_confirm(cr, uid, [id], context=context)
self.write(cr, uid, [procurement.id], {'move_id': id, 'close_move': 1})
self.write(cr, uid, [procurement.id], {'state': 'confirmed', 'message': ''})
self.write(cr, uid, ids, {'state': 'confirmed', 'message': ''})
return True
def action_move_assigned(self, cr, uid, ids, context=None):

View File

@ -14,6 +14,20 @@
<field eval="'run_scheduler'" name="function"/>
<field eval="'(False,)'" name="args"/>
</record>
<record id="sequence_proc_group_type" model="ir.sequence.type">
<field name="name">Procurement Group</field>
<field name="code">procurement.group</field>
</record>
<record id="sequence_proc_group" model="ir.sequence">
<field name="name">Procurement Group</field>
<field name="code">procurement.group</field>
<field name="prefix">PG/</field>
<field name="padding">6</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
</record>
<record id="sequence_mrp_op_type" model="ir.sequence.type">
<field name="name">Stock orderpoint</field>
@ -29,4 +43,4 @@
<field name="number_increment">1</field>
</record>
</data>
</openerp>
</openerp>

View File

@ -177,10 +177,9 @@ class product_uom(osv.osv):
return qty
amount = qty / from_unit.factor
if to_unit:
amount = amount * to_unit.factor
if round:
amount = rounding(amount * to_unit.factor, to_unit.rounding)
else:
amount = amount * to_unit.factor
amount = rounding(amount, to_unit.rounding)
return amount
def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False):

View File

@ -34,7 +34,7 @@
<record id="product_product_from" model="product.product">
<field name="supply_method">buy</field>
<field name="list_price">8.0</field>
<!-- <field name="standard_price">6.0</field>--> <!-- TODO: why this change? -->
<field name="standard_price">6.0</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="uos_id" ref="product.product_uom_kgm" />

View File

@ -39,7 +39,7 @@ class purchase_config_settings(osv.osv_memory):
'group_uom':fields.boolean("Manage different units of measure for products",
implied_group='product.group_uom',
help="""Allows you to select and maintain different units of measure for products."""),
'group_costing_method':fields.boolean("Compute product cost price based on average/FIFO/LIFO cost",
'group_costing_method':fields.boolean("The default costing method applied to all products",
implied_group='product.group_costing_method',
help="""Allows you to compute product cost price based on average cost."""),
'module_warning': fields.boolean("Alerts by products or supplier",

View File

@ -125,10 +125,9 @@ class stock_partial_picking(osv.osv_memory):
_inherit = 'stock.partial.picking'
# Overridden to inject the purchase price as true 'cost price' when processing
# incoming pickings.
# incoming pickings. The price is always stored in the company currency.
def _product_cost_for_average_update(self, cr, uid, move):
if move.picking_id.purchase_id:
#always write the cost price of products in the company currency, for easiness in further computation
currency_obj = self.pool.get("res.currency")
new_price = currency_obj.compute(cr, uid, move.picking_id.purchase_id.pricelist_id.currency_id.id, move.company_id.currency_id.id,
move.purchase_line_id.price_unit, round=False)

View File

@ -27,16 +27,6 @@ from openerp.tools.translate import _
import pytz
from openerp import SUPERUSER_ID
#COULD BE INTERESTING WHEN PROCUREMENT TO CUSTOMER AND PULL RULE
class procurement_order(osv.osv):
_inherit = 'procurement.order'
_columns = {
'sale_line_id': fields.many2one('sale.order.line', 'Sale order line'),
}
class sale_order(osv.osv):
_inherit = "sale.order"
@ -308,7 +298,6 @@ class sale_order(osv.osv):
def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, group_id = False, context=None):
mod_obj = self.pool.get('ir.model.data')
location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', 'stock_location_customers')
output_id = order.warehouse_id.lot_output_id.id
return {
'name': line.name,
'origin': order.name,
@ -320,80 +309,13 @@ class sale_order(osv.osv):
or line.product_uom_qty,
'product_uos': (line.product_uos and line.product_uos.id)\
or line.product_uom.id,
'location_id': order.warehouse_id.lot_stock_id.id, #TODO Procurement should be generated towards customers instead
'location_id': location_id,
'procure_method': line.type,
'move_id': move_id,
'company_id': order.company_id.id,
'note': line.name,
'group_id': group_id,
}
def _prepare_order_line_move(self, cr, uid, order, line, picking_id, date_planned, group_id = False, context=None):
location_id = order.warehouse_id.lot_stock_id.id
output_id = order.warehouse_id.lot_output_id.id
#mod_obj = self.pool.get('ir.model.data')
#location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', 'stock_location_customers')
return {
'name': line.name,
'picking_id': picking_id,
'product_id': line.product_id.id,
'date': date_planned,
'date_expected': date_planned,
'product_qty': line.product_uom_qty,
'product_uom': line.product_uom.id,
'product_uos_qty': (line.product_uos and line.product_uos_qty) or line.product_uom_qty,
'product_uos': (line.product_uos and line.product_uos.id)\
or line.product_uom.id,
'product_packaging': line.product_packaging.id,
'partner_id': line.address_allotment_id.id or order.partner_shipping_id.id,
'location_id': location_id,
'location_dest_id': output_id,
'sale_line_id': line.id,
'tracking_id': False,
'state': 'draft',
#'state': 'waiting',
'company_id': order.company_id.id,
'price_unit': line.product_id.standard_price or 0.0,
'group_id': group_id,
}
def _prepare_order_picking(self, cr, uid, order, context=None):
pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out')
return {
'name': pick_name,
'origin': order.name,
'date': self.date_to_datetime(cr, uid, order.date_order, context),
'type': 'out',
'state': 'auto',
'move_type': order.picking_policy,
'sale_id': order.id,
'partner_id': order.partner_shipping_id.id,
'note': order.note,
'invoice_state': (order.order_policy=='picking' and '2binvoiced') or 'none',
'company_id': order.company_id.id,
}
def ship_recreate(self, cr, uid, order, line, move_id, proc_id):
# FIXME: deals with potentially cancelled shipments, seems broken (specially if shipment has production lot)
"""
Define ship_recreate for process after shipping exception
param order: sales order to which the order lines belong
param line: sales order line records to procure
param move_id: the ID of stock move
param proc_id: the ID of procurement
"""
move_obj = self.pool.get('stock.move')
if order.state == 'shipping_except':
for pick in order.picking_ids:
for move in pick.move_lines:
if move.state == 'cancel':
mov_ids = move_obj.search(cr, uid, [('state', '=', 'cancel'),('sale_line_id', '=', line.id),('picking_id', '=', pick.id)])
if mov_ids:
for mov in move_obj.browse(cr, uid, mov_ids):
# FIXME: the following seems broken: what if move_id doesn't exist? What if there are several mov_ids? Shouldn't that be a sum?
move_obj.write(cr, uid, [move_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
self.pool.get('procurement.order').write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
return True
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
start_date = self.date_to_datetime(cr, uid, start_date, context)
@ -401,7 +323,6 @@ class sale_order(osv.osv):
date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
return date_planned
def _create_pickings_and_procurements(self, cr, uid, order, order_lines, picking_id=False, context=None):
"""Create the required procurements to supply sales order lines, also connecting
the procurements to appropriate stock moves in order to bring the goods to the
@ -421,14 +342,12 @@ class sale_order(osv.osv):
will be added. A new picking will be created if ommitted.
:return: True
"""
print "CREATE OLD PICKINGS AND PROCUREMENTS"
move_obj = self.pool.get('stock.move')
picking_obj = self.pool.get('stock.picking')
procurement_obj = self.pool.get('procurement.order')
proc_ids = []
#Create group
group_id = self.pool.get("stock.move.group").create(cr, uid, {'name': order.name}, context=context)
group_id = self.pool.get("procurement.group").create(cr, uid, {'name': order.name}, context=context)
for line in order_lines:
if line.state == 'done':
@ -436,24 +355,11 @@ class sale_order(osv.osv):
date_planned = self._get_date_planned(cr, uid, order, line, order.date_order, context=context)
if line.product_id:
if line.product_id.type in ('product', 'consu'):
if not picking_id:
picking_id = picking_obj.create(cr, uid, self._prepare_order_picking(cr, uid, order, context=context))
move_id = move_obj.create(cr, uid, self._prepare_order_line_move(cr, uid, order, line, picking_id, date_planned, group_id=group_id, context=context))
else:
# a service has no stock move
move_id = False
#TODO Need to do something instead of warehouse
if line.product_id:
proc_id = procurement_obj.create(cr, uid, self._prepare_order_line_procurement(cr, uid, order, line, move_id, date_planned, group_id = group_id, context=context))
proc_ids.append(proc_id)
line.write({'procurement_id': proc_id})
self.ship_recreate(cr, uid, order, line, move_id, proc_id)
if picking_id:
picking_obj.signal_button_confirm(cr, uid, [picking_id])
procurement_obj.signal_button_confirm(cr, uid, proc_ids)
val = {}

View File

@ -65,7 +65,7 @@ class sale_order(osv.osv):
proc_ids = []
#Create group
group_id = self.pool.get("stock.move.group").create(cr, uid, {'name': order.name}, context=context)
group_id = self.pool.get("procurement.group").create(cr, uid, {'name': order.name}, context=context)
for line in order_lines:
if line.state == 'done':
@ -130,4 +130,4 @@ class sale_order(osv.osv):
'note': line.name,
'group_id': group_id,
'state': 'draft',
}
}