_inherit = 'stock.move'
_columns= {
'procurements': fields.one2many('procurement.order', 'move_id', 'Procurements'),
+ 'group_id':fields.many2one('stock.move.group', 'Move Group'),
}
def copy_data(self, cr, uid, id, default=None, context=None):
return super(StockMove, self).copy_data(cr, uid, id, default, context=context)
+class move_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.
+ '''
+ _name = 'stock.move.group'
+ _columns = {
+ 'name': fields.char('Name'),
+ 'sequence_id': fields.many2one('ir.sequence', 'Group Sequence', help="Move group sequence"),
+ }
+
+
+
class procurement_order(osv.osv):
"""
Procurement Orders
'product_uom': fields.many2one('product.uom', 'Product Unit of Measure', required=True, states={'draft':[('readonly',False)]}, readonly=True),
'product_uos_qty': fields.float('UoS Quantity', states={'draft':[('readonly',False)]}, readonly=True),
'product_uos': fields.many2one('product.uom', 'Product UoS', states={'draft':[('readonly',False)]}, readonly=True),
- 'move_id': fields.many2one('stock.move', 'Reservation', ondelete='set null'),
'close_move': fields.boolean('Close Move at end'),
+ 'move_id': fields.many2one('stock.move', 'Reservation', ondelete='set null'),
'location_id': fields.many2one('stock.location', 'Location', required=True, states={'draft':[('readonly',False)]}, readonly=True),
'procure_method': fields.selection([('make_to_stock','Make to Stock'),('make_to_order','Make to Order')], 'Procurement Method', states={'draft':[('readonly',False)], 'confirmed':[('readonly',False)]},
readonly=True, required=True, help="If you encode manually a Procurement, you probably want to use" \
\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'),
}
_defaults = {
'state': 'draft',
@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!'),
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':
+ if procurement.procure_method == 'make_to_order':#and source != location_id: Last statement is not good
source = procurement.product_id.property_stock_procurement.id
id = move_obj.create(cr, uid, {
'name': procurement.name,
})
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, ids, {'state': 'confirmed', 'message': ''})
+ self.write(cr, uid, [procurement.id], {'state': 'confirmed', 'message': ''})
+ #Now check if all the moves of group TODO
+
+# if procurement.group_id:
+# procs = move_obj.search(cr, uid, [('group_id', '=', procurement.group_id.id), ('state', '=', 'draft')], context=context)
+#
+# #If can not find any => confirm pickings which have moves from this group
+# if not procs:
+# print "CONFIRM REST"
+# # Find pickings from this group that need to be confirmed
+# moves = move_obj.search(cr, uid, [('group_id', '=', procurement.group_id.id), ('state', '=', 'draft')], context=context)
+# pickings = []
+# for move in move_obj.browse(cr, uid, moves, context=context):
+# pickings.append(move.picking_id.id)
+# pickings = list(set(pickings))
+# if pickings:
+# self.pool.get('stock.picking').signal_button_confirm(cr, uid, pickings)
return True
def action_move_assigned(self, cr, uid, ids, context=None):
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"
elif mode == 'canceled':
return canceled
- def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, context=None):
+ 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,
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,
+ 'location_id': order.warehouse_id.lot_stock_id.id, #TODO Procurement should be generated towards customers instead
'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, context=None):
+
+ 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_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,
+ '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
+ '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 {
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
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)
+
for line in order_lines:
if line.state == 'done':
continue
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, 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
- proc_id = procurement_obj.create(cr, uid, self._prepare_order_line_procurement(cr, uid, order, line, move_id, date_planned, context=context))
+ #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)
_inherit = 'product.category'
_columns = {
- 'removal_strategy': fields.selection([('fifo', 'FIFO'), ('lifo', 'LIFO'), ('nearest', 'Nearest Location')], "Picking Strategy"),
+ 'removal_strategy': fields.selection([('fifo', 'FIFO'), ('lifo', 'LIFO'), ('nearest', 'Nearest Location')], "Standard Removal Strategy"),
'property_stock_journal': fields.property(
relation='account.journal',
type='many2one',
<field name="property_stock_valuation_account_id" domain="[('type','<>','view'), ('type','<>','consolidation')]"/>
<field name="property_stock_journal"/>
</group>
+ <group name="removal">
+ <field name="removal_strategy"/>
+ </group>
</group>
+
</data>
</field>
</record>
LEFT JOIN stock_location location ON (m.location_id = location.id)
LEFT JOIN stock_location location_dest ON (m.location_dest_id = location_dest.id)
LEFT JOIN product_template pt ON (sq.product_id=pt.id)
- WHERE location_dest.usage = 'internal' and location.usage <> 'internal'
+ WHERE (location_dest.usage = 'internal' and location.usage <> 'internal') or (sq.qty < 0) or (sq.propagated_from_id IS NOT NULL)
GROUP BY
sq.id, sq.product_id, pt.categ_id, m.partner_id, m.location_id, m.location_dest_id,
sq.prodlot_id, sq.in_date, m.state, location.usage, location_dest.usage, location.scrap_location, sq.company_id, to_char(sq.in_date, 'YYYY'), to_char(sq.in_date, 'MM'), p.name
def get_removal_strategy(self, cr, uid, id, product_id, context=None):
product = self.pool.get("product.product").browse(cr, uid, product_id, context=context)
- return product.categ_id.removal_strategy or 'fifo'
+ categ = product.categ_id
+ while (not categ.removal_strategy) and categ.parent_id:
+ categ = categ.parent_id
+ return categ.removal_strategy or None
def _product_get(self, cr, uid, id, product_ids=False, context=None, states=None):
"""
- def choose_quants(self, cr, uid, location_id, product_id, qty, context=None):
+ def choose_quants(self, cr, uid, location_id, product_id, qty, prodlot_id=False, context=None):
"""
Use the removal strategies of product to search for the correct quants
:TODOparam prodlot_id
:returns: tuples of (quant_id, qty)
"""
- #TODO Normally, you should check the removal strategy now
- #But we will assume it is FIFO for the moment
- #Will need to create search string beforehand
if self.pool.get('stock.location').get_removal_strategy(cr, uid, location_id, product_id, context=context) == 'lifo':
- possible_quants = self.search(cr, uid, [('location_id', 'child_of', location_id), ('product_id','=',product_id),
+ if prodlot_id:
+ possible_quants = self.search(cr, uid, [('location_id', 'child_of', location_id), ('product_id','=',product_id),
+ ('qty', '>', 0.0), ('reservation_id', '=', False),
+ ('prodlot_id', '=', prodlot_id)], order = 'in_date desc, id desc', context=context)
+ else:
+ possible_quants = self.search(cr, uid, [('location_id', 'child_of', location_id), ('product_id','=',product_id),
('qty', '>', 0.0), ('reservation_id', '=', False)], order = 'in_date desc, id desc', context=context)
else:
- possible_quants = self.search(cr, uid, [('location_id', 'child_of', location_id), ('product_id','=',product_id),
+ if prodlot_id:
+ possible_quants = self.search(cr, uid, [('location_id', 'child_of', location_id), ('product_id','=',product_id),
+ ('qty', '>', 0.0), ('reservation_id', '=', False),
+ ('prodlot_id', '=', prodlot_id)], order = 'in_date, id', context=context)
+ else:
+ possible_quants = self.search(cr, uid, [('location_id', 'child_of', location_id), ('product_id','=',product_id),
('qty', '>', 0.0), ('reservation_id', '=', False)], order = 'in_date, id', context=context)
qty_todo = qty
res = []
#Split for source locations
qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
- res2 = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty, context=context)
+ res2 = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty, prodlot_id = move.prodlot_id.id, context=context)
print res2
#Should group quants by location:
quants = {}
qty_from_move = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
#Check if the entire quantity has been transformed in to quants
if qty_from_move > product_qty:
- quant_tuples = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty_from_move - product_qty, context=context)
+ quant_tuples = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty_from_move - product_qty, prodlot_id = move.prodlot_id.id, context=context)
create_neg_quant = True
if quant_tuples:
quant_obj.split_and_assign_quants(cr, uid, quant_tuples, move, context=context)
self.check_total_qty(cr, uid, ids, context=context)
reconciled_quants = self.pool.get("stock.quant").move_quants(cr, uid, quants[move.id], move, context=context)
quants[move.id] += reconciled_quants
- #Generate negative quants if necessary
#Do price calculation on move -> Should pass Quants here -> is a dictionary
#
##############################################################################
-from openerp.osv import osv
+from openerp.osv import osv, fields
from openerp.tools.translate import _
+
+
+
class procurement_order(osv.osv):
_inherit = 'procurement.order'
+
+
+
def check_buy(self, cr, uid, ids, context=None):
for procurement in self.browse(cr, uid, ids, context=context):
for line in procurement.product_id.flow_pull_ids:
return False
def action_move_create(self, cr, uid, ids, context=None):
+ #Create moves from
proc_obj = self.pool.get('procurement.order')
move_obj = self.pool.get('stock.move')
picking_obj=self.pool.get('stock.picking')
break
assert line, 'Line cannot be False if we are on this state of the workflow'
origin = (proc.origin or proc.name or '').split(':')[0] +':'+line.name
- picking_id = picking_obj.create(cr, uid, {
- 'origin': origin,
- 'company_id': line.company_id and line.company_id.id or False,
- 'type': line.picking_type,
- 'stock_journal_id': line.journal_id and line.journal_id.id or False,
- 'move_type': 'one',
- 'partner_id': line.partner_address_id.id,
- 'note': _('Picking for pulled procurement coming from original location %s, pull rule %s, via original Procurement %s (#%d)') % (proc.location_id.name, line.name, proc.name, proc.id),
- 'invoice_state': line.invoice_state,
- })
+ #First do a search for moves which would not already have this picking:
+ moves = move_obj.search(cr, uid, [('group_id', '=', proc.group_id.id), ('location_id', '=', line.location_src_id.id),
+ ('location_dest_id', '=', line.location_id.id),
+ ], context=context)
+ print "moves, ", moves, proc.group_id.id
+ if moves and move_obj.browse(cr, uid, moves[0], context=context).picking_id:
+ picking_id = move_obj.browse(cr, uid, moves[0], context=context).picking_id.id
+ else:
+ picking_id = picking_obj.create(cr, uid, {
+ 'origin': origin,
+ 'company_id': line.company_id and line.company_id.id or False,
+ 'type': line.picking_type,
+ 'stock_journal_id': line.journal_id and line.journal_id.id or False,
+ 'move_type': 'one',
+ 'partner_id': line.partner_address_id.id,
+ 'note': _('Picking for pulled procurement coming from original location %s, pull rule %s, via original Procurement %s (#%d)') % (proc.location_id.name, line.name, proc.name, proc.id),
+ 'invoice_state': line.invoice_state,
+ })
move_id = move_obj.create(cr, uid, {
'name': line.name,
'picking_id': picking_id,
'move_dest_id': proc.move_id and proc.move_id.id or False, # to verif, about history ?
'tracking_id': False,
'cancel_cascade': line.cancel_cascade,
+ 'group_id': proc.group_id.id,
'state': 'confirmed',
'note': _('Move for pulled procurement coming from original location %s, pull rule %s, via original Procurement %s (#%d)') % (proc.location_id.name, line.name, proc.name, proc.id),
})
or proc.product_uom.id,
'location_id': line.location_src_id.id,
'procure_method': line.procure_method,
- 'move_id': move_id,
+ 'move_id': move_id,
+ 'group_id': proc.group_id.id,
})
self.pool.get('stock.picking').signal_button_confirm(cr, uid, [picking_id])
+
self.signal_button_confirm(cr, uid, [proc_id])
if proc.move_id:
move_obj.write(cr, uid, [proc.move_id.id],
_description = 'Put Away Strategy'
_columns = {
'product_ids':fields.function(_calc_product_ids, "Products"),
- 'product_categ_id':fields.many2one('product.category', 'Product Category'),
- 'location_id': fields.many2one('stock.location','Parent Location', help="Parent Destination Location from which a child bin location needs to be chosen"), #domain=[('type', '=', 'parent')],
- 'method': fields.selection([('nearest_empty','Nearest Empty Location'), ('add_or_nearest_empty', 'Try to add on another location, otherwise nearest empty'), ('L2R', 'left to right'), ('R2L', 'right to left'),
- ('high2low', 'high to low'), ('low2high', 'low to high'), ('fixed', 'Fixed Location')], "Method"),
+ 'product_categ_id':fields.many2one('product.category', 'Product Category', required=True),
+ 'location_id': fields.many2one('stock.location','Parent Location', help="Parent Destination Location from which a child bin location needs to be chosen", required=True), #domain=[('type', '=', 'parent')],
+ 'method': fields.selection([('empty', 'Empty'), ('fixed', 'Fixed Location')], "Method", required = True),
}
_description = 'Removal Strategy'
_columns = {
'product_ids':fields.function(_calc_product_ids, "Products"),
- 'product_categ_id':fields.many2one('product.category', 'Product Category'),
- 'location_id': fields.many2one('stock.location', 'Parent Location', help="Parent Source Location from which a child bin location needs to be chosen"), #, domain=[('type', '=', 'parent')]
- 'method': fields.selection([('fifo', 'FIFO'), ('lifo', 'LIFO'), ('nearest', 'Nearest location')], "Method"),
+ 'product_categ_id':fields.many2one('product.category', 'Product Category', required=True),
+ 'location_id': fields.many2one('stock.location', 'Parent Location', help="Parent Source Location from which a child bin location needs to be chosen", required=True), #, domain=[('type', '=', 'parent')]
+ 'method': fields.selection([('fifo', 'FIFO'), ('lifo', 'LIFO')], "Method", required=True),
}
return strats and strats[0] or 'nearest'
def get_removal_strategy(self, cr, uid, id, product_id, context=None):
+ #TODO improve code
product = self.pool.get("product.product").browse(cr, uid, product_id, context=context)
- strats = self.pool.get('product.removal').search(cr, uid, [('location_id','=',id), ('product_categ_id','child_of', product.categ_id.id)], context=context) #Also child_of for location???
+ strats = self.pool.get('product.removal').search(cr, uid, [('location_id','=',id), ('product_categ_id','=', product.categ_id.id)], context=context) #Also child_of for location???
if not strats:
strat = product.categ_id.removal_strategy
else:
strat = strats[0]
return strat or product.categ_id.removal_strategy or 'fifo'
+
+ return super(stock_location, self).get_removal_strategy(cr, uid, id, product_id, context=context)
+
def chained_location_get(self, cr, uid, location, partner=None, product=None, context=None):
if product:
--- /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/>.
+#
+##############################################################################
+
+import stock_location_sale
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
--- /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/>.
+#
+##############################################################################
+
+
+{
+ 'name': 'Advanced Routes with sales',
+ 'version': '1.0',
+ 'category': 'Manufacturing',
+ 'description': """
+Cross-module for stock_location and sale such that a sale order generates a procurement in stock instead
+ """,
+ 'author': 'OpenERP SA',
+ 'images': [],
+ 'depends': ['sale', 'stock_location'],
+ 'data': [],
+ 'demo': [
+ # 'stock_location_demo_cpu1.xml',
+ # 'stock_location_demo_cpu3.yml',
+ ],
+ 'installable': True,
+ 'test': [
+ # 'test/stock_location_pull_flow.yml',
+ # 'test/stock_location_push_flow.yml',
+ ],
+ 'auto_install': False,
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
--- /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 fields, osv
+from openerp.tools.translate import _
+
+
+class sale_order(osv.osv):
+
+ _inherit = "sale.order"
+
+
+
+
+
+ def action_ship_create(self, cr, uid, ids, context=None):
+ print "acitonshipcreate"
+ for order in self.browse(cr, uid, ids, context=context):
+ self._create_pickings_and_procurements(cr, uid, order, order.order_line, None, context=context)
+ return True
+
+
+ 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
+ sales order's requested location.
+
+ If ``picking_id`` is provided, the stock moves will be added to it, otherwise
+ a standard outgoing picking will be created to wrap the stock moves, as returned
+ by :meth:`~._prepare_order_picking`.
+
+ Modules that wish to customize the procurements or partition the stock moves over
+ multiple stock pickings may override this method and call ``super()`` with
+ different subsets of ``order_lines`` and/or preset ``picking_id`` values.
+
+ :param browse_record order: sales order to which the order lines belong
+ :param list(browse_record) order_lines: sales order line records to procure
+ :param int picking_id: optional ID of a stock picking to which the created stock moves
+ will be added. A new picking will be created if omitted.
+ :return: True
+ """
+ print "Create 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)
+
+ for line in order_lines:
+ if line.state == 'done':
+ continue
+
+ 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, [], 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 = {}
+ if order.state == 'shipping_except':
+ val['state'] = 'progress'
+ val['shipped'] = False
+
+ if (order.order_policy == 'manual'):
+ for line in order.order_line:
+ if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
+ val['state'] = 'manual'
+ break
+ order.write(val)
+ return True
+
+
+
+ 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,
+ 'date_planned': date_planned,
+ 'product_id': line.product_id.id,
+ '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,
+ '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,
+ 'state': 'draft',
+ }
\ No newline at end of file