[CLEAN] stock: pre-migration cleaning
General remarks concerning cleaning commits preparing the stock migration ========================================================================= Small update / cleaning before moving and migrating. This commit contains the cleaning of stock_picking_type and stock_picking models. The first cleaning performed is to clean methods having a browse record or a list of records replacing ids parameter. Those are converted into classic old API methods using cr, uid, ids. This eases the migration as they are then migrated into multi methods. Another cleaning concerns naming things. Some methods are renamed to ease the code readability. Some parameters are also renamed as well as some variables. This kind of change is performed only when the readability is improved. Otherwise the code is kept as it is to avoid rewriting too much of the code. Finally unnecessary stuff is also removed. This concerns dead code (methods not used in community nor in enterprise) and unnecessary code splitting (tools methods called once without real added value are directly put into their called method). - stock.move: no specific changes; note that a method called only in mrp has been moved to mrp. - product: no specific changes - config settings: no specific changes - wizards: no specific changes stock.quant main changes ======================== - ``apply_removal_strategy`` method updated to return only the removal strategy instead of having a mix of several things (overrides updated) - ``quants_get_**`` methods renamed to ease code understanding - quants_unreserve from stock.quant to stock.move model because its primary record is a move, not quants stock.inventory and stock.inventory.line main changes ===================================================== - stock.inventory: ``move_ids_exist`` field remove. Unused. stock.picking and stock.picking.type main changes ================================================= - stock.picking: ``move_lines_related`` is removed. Indeed it is used only to display a slightly different view of moves contained inside a picking. However this field causes a lot of issues when migrated into the new API. The view is updated to keep the same look and feel while avoiding an unnecessary field. - stock.picking.type: complete_name field is removed. Using display_name is sufficient for the existing use cases. stock.warehouse and stock.orderpoint main changes ================================================= - stock.warehouse: removed ``resupply_from_wh``, unused field stock.pack.operation main changes ================================= - stock.pack.operation: ``processed_boolean`` fields renamed to ``is_done`` to match its use in the code. stock.location main changes =========================== Note that in this commit a strange override in create has been replaced by a cleaner override in default_get in order to have something more understandable procurement main changes ======================== - in this commit some code located in procurement has been moved to the orderpoint model. Indeed those methods take an orderpoint as main argument, making it more orderpoint methods than procurement methods - ``_prepare_orderpoint_procurement`` method has been merged with its strange override in stock_calendar to have something a bit more modular
This commit is contained in:
+3
-3
@@ -1178,12 +1178,12 @@ class mrp_production(osv.osv):
|
||||
move = stock_move.browse(cr, uid, move_id, context=context)
|
||||
src_loc = loc_obj.browse(cr, uid, source_location_id, context=context)
|
||||
dest_loc = loc_obj.browse(cr, uid, dest_location_id, context=context)
|
||||
code = stock_move.get_code_from_locs(cr, uid, move, src_loc, dest_loc, context=context)
|
||||
code = stock_move.get_code_from_locs(cr, uid, [move.id], src_loc, dest_loc, context=context)
|
||||
if code == 'outgoing':
|
||||
check_loc = src_loc
|
||||
else:
|
||||
check_loc = dest_loc
|
||||
wh = loc_obj.get_warehouse(cr, uid, check_loc, context=context)
|
||||
wh = loc_obj.get_warehouse(cr, uid, [check_loc.id], context=context)
|
||||
domain = [('code', '=', code)]
|
||||
if wh:
|
||||
domain += [('warehouse_id', '=', wh)]
|
||||
@@ -1230,7 +1230,7 @@ class mrp_production(osv.osv):
|
||||
#this saves us a browse in create()
|
||||
'price_unit': product.standard_price,
|
||||
'origin': production.name,
|
||||
'warehouse_id': loc_obj.get_warehouse(cr, uid, production.location_src_id, context=context),
|
||||
'warehouse_id': loc_obj.get_warehouse(cr, uid, [production.location_src_id.id], context=context),
|
||||
'group_id': production.move_prod_id.group_id.id,
|
||||
}, context=context)
|
||||
|
||||
|
||||
@@ -29,16 +29,18 @@ class procurement_order(osv.osv):
|
||||
self.pool.get('mrp.production').action_cancel(cr, uid, [procurement.production_id.id], context=context)
|
||||
return super(procurement_order, self).propagate_cancels(cr, uid, ids, context=context)
|
||||
|
||||
def _run(self, cr, uid, procurement, context=None):
|
||||
def _run(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
if procurement.rule_id and procurement.rule_id.action == 'manufacture':
|
||||
#make a manufacturing order for the procurement
|
||||
return self.make_mo(cr, uid, [procurement.id], context=context)[procurement.id]
|
||||
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
|
||||
return super(procurement_order, self)._run(cr, uid, ids, context=context)
|
||||
|
||||
def _check(self, cr, uid, procurement, context=None):
|
||||
def _check(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
if procurement.production_id and procurement.production_id.state == 'done': # TOCHECK: no better method?
|
||||
return True
|
||||
return super(procurement_order, self)._check(cr, uid, procurement, context=context)
|
||||
return super(procurement_order, self)._check(cr, uid, ids, context=context)
|
||||
|
||||
def check_bom_exists(self, cr, uid, ids, context=None):
|
||||
""" Finds the bill of material for the product from procurement order.
|
||||
|
||||
+30
-9
@@ -19,8 +19,26 @@ class StockMove(osv.osv):
|
||||
'consumed_for': fields.many2one('stock.move', 'Consumed for', help='Technical field used to make the traceability of produced products'),
|
||||
}
|
||||
|
||||
def check_tracking(self, cr, uid, move, ops, context=None):
|
||||
super(StockMove, self).check_tracking(cr, uid, move, ops, context=context)
|
||||
def get_code_from_locs(self, cr, uid, ids, location_id=False, location_dest_id=False, context=None):
|
||||
"""
|
||||
Returns the code the picking type should have. This can easily be used
|
||||
to check if a move is internal or not
|
||||
move, location_id and location_dest_id are browse records
|
||||
"""
|
||||
move = self.browse(cr, uid, ids[0], context=context)
|
||||
# TDE note: called only in MRP
|
||||
code = 'internal'
|
||||
src_loc = location_id or move.location_id
|
||||
dest_loc = location_dest_id or move.location_dest_id
|
||||
if src_loc.usage == 'internal' and dest_loc.usage != 'internal':
|
||||
code = 'outgoing'
|
||||
if src_loc.usage != 'internal' and dest_loc.usage == 'internal':
|
||||
code = 'incoming'
|
||||
return code
|
||||
|
||||
def check_tracking(self, cr, uid, ids, ops, context=None):
|
||||
super(StockMove, self).check_tracking(cr, uid, ids, ops, context=context)
|
||||
move = self.browse(cr, uid, ids[0], context=context)
|
||||
if move.raw_material_production_id and move.product_id.tracking!='none' and move.location_dest_id.usage == 'production' and move.raw_material_production_id.product_id.tracking != 'none' and not move.consumed_for:
|
||||
raise UserError(_("Because the product %s requires it, you must assign a serial number to your raw material %s to proceed further in your production. Please use the 'Produce' button to do so.") % (move.raw_material_production_id.product_id.name, move.product_id.name))
|
||||
|
||||
@@ -152,7 +170,7 @@ class StockMove(osv.osv):
|
||||
# Compare with numbers of move uom as we want to avoid a split with 0 qty
|
||||
quantity_rest_uom = move.product_uom_qty - self.pool.get("product.uom")._compute_qty_obj(cr, uid, move.product_id.uom_id, product_qty, move.product_uom)
|
||||
if float_compare(quantity_rest_uom, 0, precision_rounding=move.product_uom.rounding) != 0:
|
||||
new_mov = self.split(cr, uid, move, quantity_rest, context=context)
|
||||
new_mov = self.split(cr, uid, [move.id], quantity_rest, context=context)
|
||||
if move.production_id:
|
||||
self.write(cr, uid, [new_mov], {'production_id': move.production_id.id}, context=context)
|
||||
res.append(new_mov)
|
||||
@@ -237,9 +255,10 @@ class stock_warehouse(osv.osv):
|
||||
'warehouse_id': warehouse.id,
|
||||
}
|
||||
|
||||
def create_routes(self, cr, uid, ids, warehouse, context=None):
|
||||
def create_routes(self, cr, uid, ids, context=None):
|
||||
pull_obj = self.pool.get('procurement.rule')
|
||||
res = super(stock_warehouse, self).create_routes(cr, uid, ids, warehouse, context=context)
|
||||
res = super(stock_warehouse, self).create_routes(cr, uid, ids, context=context)
|
||||
warehouse = self.browse(cr, uid, ids, context=context)[0]
|
||||
if warehouse.manufacture_to_resupply:
|
||||
manufacture_pull_vals = self._get_manufacture_pull_rule(cr, uid, warehouse, context=context)
|
||||
manufacture_pull_id = pull_obj.create(cr, uid, manufacture_pull_vals, context=context)
|
||||
@@ -264,14 +283,16 @@ class stock_warehouse(osv.osv):
|
||||
pull_obj.unlink(cr, uid, warehouse.manufacture_pull_id.id, context=context)
|
||||
return super(stock_warehouse, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
def get_all_routes_for_wh(self, cr, uid, warehouse, context=None):
|
||||
all_routes = super(stock_warehouse, self).get_all_routes_for_wh(cr, uid, warehouse, context=context)
|
||||
def get_all_routes_for_wh(self, cr, uid, ids, context=None):
|
||||
all_routes = super(stock_warehouse, self).get_all_routes_for_wh(cr, uid, ids, context=context)
|
||||
warehouse = self.browse(cr, uid, ids[0], context=context)
|
||||
if warehouse.manufacture_to_resupply and warehouse.manufacture_pull_id and warehouse.manufacture_pull_id.route_id:
|
||||
all_routes += [warehouse.manufacture_pull_id.route_id.id]
|
||||
return all_routes
|
||||
|
||||
def _handle_renaming(self, cr, uid, warehouse, name, code, context=None):
|
||||
res = super(stock_warehouse, self)._handle_renaming(cr, uid, warehouse, name, code, context=context)
|
||||
def _handle_renaming(self, cr, uid, ids, name, code, context=None):
|
||||
res = super(stock_warehouse, self)._handle_renaming(cr, uid, ids, name, code, context=context)
|
||||
warehouse = self.browse(cr, uid, ids[0], context=context)
|
||||
pull_obj = self.pool.get('procurement.rule')
|
||||
#change the manufacture procurement rule name
|
||||
if warehouse.manufacture_pull_id:
|
||||
|
||||
@@ -170,12 +170,9 @@ class procurement_order(osv.osv):
|
||||
return {'value': v}
|
||||
return {}
|
||||
|
||||
def get_cancel_ids(self, cr, uid, ids, context=None):
|
||||
return [proc.id for proc in self.browse(cr, uid, ids, context=context) if proc.state != 'done']
|
||||
|
||||
def cancel(self, cr, uid, ids, context=None):
|
||||
#cancel only the procurements that aren't done already
|
||||
to_cancel_ids = self.get_cancel_ids(cr, uid, ids, context=context)
|
||||
to_cancel_ids = [proc.id for proc in self.browse(cr, uid, ids, context=context) if proc.state != 'done']
|
||||
if to_cancel_ids:
|
||||
return self.write(cr, uid, to_cancel_ids, {'state': 'cancel'}, context=context)
|
||||
|
||||
@@ -190,8 +187,8 @@ class procurement_order(osv.osv):
|
||||
procurement = self.browse(cr, uid, procurement_id, context=context)
|
||||
if procurement.state not in ("running", "done"):
|
||||
try:
|
||||
if self._assign(cr, uid, procurement, context=context):
|
||||
res = self._run(cr, uid, procurement, context=context or {})
|
||||
if self._assign(cr, uid, [procurement.id], context=context):
|
||||
res = self._run(cr, uid, [procurement.id], context=context or {})
|
||||
if res:
|
||||
self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context)
|
||||
else:
|
||||
@@ -213,7 +210,7 @@ class procurement_order(osv.osv):
|
||||
done_ids = []
|
||||
for procurement in self.browse(cr, uid, ids, context=context):
|
||||
try:
|
||||
result = self._check(cr, uid, procurement, context=context)
|
||||
result = self._check(cr, uid, [procurement.id], context=context)
|
||||
if result:
|
||||
done_ids.append(procurement.id)
|
||||
if autocommit:
|
||||
@@ -231,41 +228,38 @@ class procurement_order(osv.osv):
|
||||
#
|
||||
# Method to overwrite in different procurement modules
|
||||
#
|
||||
def _find_suitable_rule(self, cr, uid, procurement, context=None):
|
||||
def _find_suitable_rule(self, cr, uid, ids, context=None):
|
||||
'''This method returns a procurement.rule that depicts what to do with the given procurement
|
||||
in order to complete its needs. It returns False if no suiting rule is found.
|
||||
:param procurement: browse record
|
||||
:rtype: int or False
|
||||
'''
|
||||
return False
|
||||
|
||||
def _assign(self, cr, uid, procurement, context=None):
|
||||
def _assign(self, cr, uid, ids, context=None):
|
||||
'''This method check what to do with the given procurement in order to complete its needs.
|
||||
It returns False if no solution is found, otherwise it stores the matching rule (if any) and
|
||||
returns True.
|
||||
:param procurement: browse record
|
||||
:rtype: boolean
|
||||
'''
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
#if the procurement already has a rule assigned, we keep it (it has a higher priority as it may have been chosen manually)
|
||||
if procurement.rule_id:
|
||||
return True
|
||||
elif procurement.product_id.type not in ('service', 'digital'):
|
||||
rule_id = self._find_suitable_rule(cr, uid, procurement, context=context)
|
||||
rule_id = self._find_suitable_rule(cr, uid, ids, context=context)
|
||||
if rule_id:
|
||||
self.write(cr, uid, [procurement.id], {'rule_id': rule_id}, context=context)
|
||||
return True
|
||||
return False
|
||||
|
||||
def _run(self, cr, uid, procurement, context=None):
|
||||
def _run(self, cr, uid, ids, context=None):
|
||||
'''This method implements the resolution of the given procurement
|
||||
:param procurement: browse record
|
||||
:returns: True if the resolution of the procurement was a success, False otherwise to set it in exception
|
||||
'''
|
||||
return True
|
||||
|
||||
def _check(self, cr, uid, procurement, context=None):
|
||||
def _check(self, cr, uid, ids, context=None):
|
||||
'''Returns True if the given procurement is fulfilled, False otherwise
|
||||
:param procurement: browse record
|
||||
:rtype: boolean
|
||||
'''
|
||||
return False
|
||||
|
||||
@@ -10,7 +10,7 @@ class StockQuant(models.Model):
|
||||
removal_date = fields.Datetime(related='lot_id.removal_date', store=True)
|
||||
|
||||
@api.model
|
||||
def apply_removal_strategy(self, qty, move, ops=False, domain=None, removal_strategy='fifo'):
|
||||
def _quants_removal_get_order(self, removal_strategy):
|
||||
if removal_strategy == 'fefo':
|
||||
return self._quants_get_order(qty, move, ops=ops, domain=domain, orderby='removal_date, in_date, id')
|
||||
return super(StockQuant, self).apply_removal_strategy(qty, move, ops=ops, domain=domain, removal_strategy=removal_strategy)
|
||||
return 'removal_date, in_date, id'
|
||||
return super(StockQuant, self)._quants_removal_get_order(removal_strategy=removal_strategy)
|
||||
|
||||
+12
-11
@@ -339,6 +339,7 @@ class PurchaseOrder(models.Model):
|
||||
|
||||
for pick in order.picking_ids.filtered(lambda r: r.state != 'cancel'):
|
||||
pick.action_cancel()
|
||||
# TDE FIXME: I don' think context key is necessary, as actions are not related / called from each other
|
||||
if not self.env.context.get('cancel_procurement'):
|
||||
procurements = order.order_line.mapped('procurement_ids')
|
||||
procurements.filtered(lambda r: r.state not in ('cancel', 'exception') and r.rule_id.propagate).write({'state': 'cancel'})
|
||||
@@ -811,19 +812,19 @@ class ProcurementOrder(models.Model):
|
||||
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _run(self, procurement):
|
||||
if procurement.rule_id and procurement.rule_id.action == 'buy':
|
||||
return procurement.make_po()
|
||||
return super(ProcurementOrder, self)._run(procurement)
|
||||
@api.multi
|
||||
def _run(self):
|
||||
if self.rule_id and self.rule_id.action == 'buy':
|
||||
return self.make_po()
|
||||
return super(ProcurementOrder, self)._run()
|
||||
|
||||
@api.model
|
||||
def _check(self, procurement):
|
||||
if procurement.purchase_line_id:
|
||||
if not procurement.move_ids:
|
||||
@api.multi
|
||||
def _check(self):
|
||||
if self.purchase_line_id:
|
||||
if not self.move_ids:
|
||||
return False
|
||||
return all(move.state == 'done' for move in procurement.move_ids)
|
||||
return super(ProcurementOrder, self)._check(procurement)
|
||||
return all(move.state == 'done' for move in self.move_ids)
|
||||
return super(ProcurementOrder, self)._check()
|
||||
|
||||
@api.v8
|
||||
def _get_purchase_schedule_date(self):
|
||||
|
||||
+22
-16
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp import api
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.exceptions import UserError
|
||||
@@ -29,22 +30,23 @@ class stock_move(osv.osv):
|
||||
readonly=True),
|
||||
}
|
||||
|
||||
def get_price_unit(self, cr, uid, move, context=None):
|
||||
@api.multi
|
||||
def get_price_unit(self):
|
||||
""" Returns the unit price to store on the quant """
|
||||
if move.purchase_line_id:
|
||||
order = move.purchase_line_id.order_id
|
||||
if self.purchase_line_id:
|
||||
order = self.purchase_line_id.order_id
|
||||
#if the currency of the PO is different than the company one, the price_unit on the move must be reevaluated
|
||||
#(was created at the rate of the PO confirmation, but must be valuated at the rate of stock move execution)
|
||||
if order.currency_id != move.company_id.currency_id:
|
||||
if order.currency_id != self.company_id.currency_id:
|
||||
#we don't pass the move.date in the compute() for the currency rate on purpose because
|
||||
# 1) get_price_unit() is supposed to be called only through move.action_done(),
|
||||
# 2) the move hasn't yet the correct date (currently it is the expected date, after
|
||||
# completion of action_done() it will be now() )
|
||||
price_unit = move.purchase_line_id._get_stock_move_price_unit()
|
||||
move.write({'price_unit': price_unit})
|
||||
price_unit = self.purchase_line_id._get_stock_move_price_unit()
|
||||
self.write({'price_unit': price_unit})
|
||||
return price_unit
|
||||
return move.price_unit
|
||||
return super(stock_move, self).get_price_unit(cr, uid, move, context=context)
|
||||
return self.price_unit
|
||||
return super(stock_move, self).get_price_unit()
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
default = default or {}
|
||||
@@ -87,9 +89,10 @@ class stock_warehouse(osv.osv):
|
||||
'group_propagation_option': 'none',
|
||||
}
|
||||
|
||||
def create_routes(self, cr, uid, ids, warehouse, context=None):
|
||||
def create_routes(self, cr, uid, ids, context=None):
|
||||
pull_obj = self.pool.get('procurement.rule')
|
||||
res = super(stock_warehouse, self).create_routes(cr, uid, ids, warehouse, context=context)
|
||||
res = super(stock_warehouse, self).create_routes(cr, uid, ids, context=context)
|
||||
warehouse = self.browse(cr, uid, ids, context=context)[0]
|
||||
if warehouse.buy_to_resupply:
|
||||
buy_pull_vals = self._get_buy_pull_rule(cr, uid, warehouse, context=context)
|
||||
buy_pull_id = pull_obj.create(cr, uid, buy_pull_vals, context=context)
|
||||
@@ -114,8 +117,9 @@ class stock_warehouse(osv.osv):
|
||||
buy_pull_id = pull_obj.unlink(cr, uid, warehouse.buy_pull_id.id, context=context)
|
||||
return super(stock_warehouse, self).write(cr, uid, ids, vals, context=None)
|
||||
|
||||
def get_all_routes_for_wh(self, cr, uid, warehouse, context=None):
|
||||
all_routes = super(stock_warehouse, self).get_all_routes_for_wh(cr, uid, warehouse, context=context)
|
||||
def get_all_routes_for_wh(self, cr, uid, ids, context=None):
|
||||
all_routes = super(stock_warehouse, self).get_all_routes_for_wh(cr, uid, ids, context=context)
|
||||
warehouse = self.browse(cr, uid, ids[0], context=context)
|
||||
if warehouse.buy_to_resupply and warehouse.buy_pull_id and warehouse.buy_pull_id.route_id:
|
||||
all_routes += [warehouse.buy_pull_id.route_id.id]
|
||||
return all_routes
|
||||
@@ -130,16 +134,18 @@ class stock_warehouse(osv.osv):
|
||||
break
|
||||
return res
|
||||
|
||||
def _handle_renaming(self, cr, uid, warehouse, name, code, context=None):
|
||||
res = super(stock_warehouse, self)._handle_renaming(cr, uid, warehouse, name, code, context=context)
|
||||
def _handle_renaming(self, cr, uid, ids, name, code, context=None):
|
||||
res = super(stock_warehouse, self)._handle_renaming(cr, uid, ids, name, code, context=context)
|
||||
warehouse = self.browse(cr, uid, ids[0], context=context)
|
||||
pull_obj = self.pool.get('procurement.rule')
|
||||
#change the buy procurement rule name
|
||||
if warehouse.buy_pull_id:
|
||||
pull_obj.write(cr, uid, warehouse.buy_pull_id.id, {'name': warehouse.buy_pull_id.name.replace(warehouse.name, name, 1)}, context=context)
|
||||
return res
|
||||
|
||||
def change_route(self, cr, uid, ids, warehouse, new_reception_step=False, new_delivery_step=False, context=None):
|
||||
res = super(stock_warehouse, self).change_route(cr, uid, ids, warehouse, new_reception_step=new_reception_step, new_delivery_step=new_delivery_step, context=context)
|
||||
def change_route(self, cr, uid, ids, new_reception_step=False, new_delivery_step=False, context=None):
|
||||
res = super(stock_warehouse, self).change_route(cr, uid, ids, new_reception_step=new_reception_step, new_delivery_step=new_delivery_step, context=context)
|
||||
warehouse = self.browse(cr, uid, ids[0], context=context)
|
||||
if warehouse.in_type_id.default_location_dest_id != warehouse.buy_pull_id.location_id:
|
||||
self.pool.get('procurement.rule').write(cr, uid, warehouse.buy_pull_id.id, {'location_id': warehouse.in_type_id.default_location_dest_id.id}, context=context)
|
||||
return res
|
||||
|
||||
@@ -70,11 +70,11 @@ class SaleOrderLine(models.Model):
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
@api.model
|
||||
def _prepare_procurement_from_move(self, move):
|
||||
res = super(StockMove, self)._prepare_procurement_from_move(move)
|
||||
if res and move.procurement_id and move.procurement_id.property_ids:
|
||||
res['property_ids'] = [(6, 0, move.procurement_id.property_ids.ids)]
|
||||
@api.multi
|
||||
def _prepare_procurement_from_move(self):
|
||||
res = super(StockMove, self)._prepare_procurement_from_move()
|
||||
if res and self.procurement_id and self.procurement_id.property_ids:
|
||||
res['property_ids'] = [(6, 0, self.procurement_id.property_ids.ids)]
|
||||
return res
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -265,9 +265,9 @@ class AccountInvoice(models.Model):
|
||||
class ProcurementOrder(models.Model):
|
||||
_inherit = "procurement.order"
|
||||
|
||||
@api.model
|
||||
def _run_move_create(self, procurement):
|
||||
vals = super(ProcurementOrder, self)._run_move_create(procurement)
|
||||
@api.multi
|
||||
def _run_move_create(self):
|
||||
vals = super(ProcurementOrder, self)._run_move_create()
|
||||
if self.sale_line_id:
|
||||
vals.update({'sequence': self.sale_line_id.sequence})
|
||||
return vals
|
||||
|
||||
@@ -14,21 +14,24 @@ class procurement_order(osv.osv):
|
||||
'task_id': fields.many2one('project.task', 'Task', copy=False),
|
||||
}
|
||||
|
||||
def _is_procurement_task(self, cr, uid, procurement, context=None):
|
||||
def _is_procurement_task(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
return procurement.product_id.type == 'service' and procurement.product_id.track_service=='task' or False
|
||||
|
||||
def _assign(self, cr, uid, procurement, context=None):
|
||||
res = super(procurement_order, self)._assign(cr, uid, procurement, context=context)
|
||||
def _assign(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
res = super(procurement_order, self)._assign(cr, uid, ids, context=context)
|
||||
if not res:
|
||||
#if there isn't any specific procurement.rule defined for the product, we may want to create a task
|
||||
return self._is_procurement_task(cr, uid, procurement, context=context)
|
||||
return procurement._is_procurement_task()
|
||||
return res
|
||||
|
||||
def _run(self, cr, uid, procurement, context=None):
|
||||
if self._is_procurement_task(cr, uid, procurement, context=context) and not procurement.task_id:
|
||||
def _run(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
if procurement._is_procurement_task() and not procurement.task_id:
|
||||
#create a task for the procurement
|
||||
return self._create_service_task(cr, uid, procurement, context=context)
|
||||
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
|
||||
return super(procurement_order, self)._run(cr, uid, ids, context=context)
|
||||
|
||||
def _convert_qty_company_hours(self, cr, uid, procurement, context=None):
|
||||
product_uom = self.pool.get('product.uom')
|
||||
|
||||
+93
-222
@@ -6,6 +6,8 @@ from openerp.tools.translate import _
|
||||
|
||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, float_compare, float_round
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
from collections import defaultdict
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import datetime
|
||||
from psycopg2 import OperationalError
|
||||
@@ -89,7 +91,8 @@ class procurement_order(osv.osv):
|
||||
self.propagate_cancels(cr, uid, to_cancel_ids, context=ctx)
|
||||
return super(procurement_order, self).cancel(cr, uid, to_cancel_ids, context=ctx)
|
||||
|
||||
def _find_parent_locations(self, cr, uid, procurement, context=None):
|
||||
def _find_parent_locations(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
location = procurement.location_id
|
||||
res = [location.id]
|
||||
while location.location_id:
|
||||
@@ -103,141 +106,9 @@ class procurement_order(osv.osv):
|
||||
return {'value': {'location_id': warehouse.lot_stock_id.id}}
|
||||
return {}
|
||||
|
||||
#Doing assignation, ... in multi
|
||||
def _assign_multi(self, cr, uid, procurements, context=None):
|
||||
res = {}
|
||||
todo_procs = []
|
||||
context = context or {}
|
||||
for procurement in procurements:
|
||||
if procurement.rule_id:
|
||||
res[procurement.id] = True
|
||||
elif procurement.product_id.type in ['product', 'consu']:
|
||||
todo_procs += [procurement]
|
||||
|
||||
res_dict = self._find_suitable_rule_multi(cr, uid, todo_procs, context=context)
|
||||
rule_dict = {}
|
||||
for proc in res_dict.keys():
|
||||
if res_dict[proc]:
|
||||
if rule_dict.get(res_dict[proc]):
|
||||
rule_dict[res_dict[proc]] += [proc]
|
||||
else:
|
||||
rule_dict[res_dict[proc]] = [proc]
|
||||
|
||||
for rule in rule_dict.keys():
|
||||
self.write(cr, uid, rule_dict[rule], {'rule_id': rule}, context=context)
|
||||
|
||||
|
||||
def _get_route_group_dict(self, cr, uid, procurements, context=None):
|
||||
"""
|
||||
Returns a dictionary with key the routes and values the products associated
|
||||
"""
|
||||
ids = [x.id for x in procurements]
|
||||
cr.execute("""
|
||||
SELECT proc_id, route_id FROM
|
||||
((SELECT p.id AS proc_id, route_id
|
||||
FROM stock_route_product AS link, procurement_order AS p, product_template AS pt, product_product pp
|
||||
WHERE pp.product_tmpl_id = pt.id AND link.product_id = pt.id AND pp.id = p.product_id
|
||||
AND p.id in %s)
|
||||
UNION (SELECT p.id AS proc_id, link.route_id AS route_id
|
||||
FROM stock_location_route_categ AS link, product_product AS pp, procurement_order AS p,
|
||||
product_template AS pt, product_category AS pc, product_category AS pc_product
|
||||
WHERE p.product_id = pp.id AND pp.product_tmpl_id = pt.id AND pc_product.id = pt.categ_id AND
|
||||
pc.parent_left <= pc_product.parent_left AND pc.parent_right >= pc_product.parent_left
|
||||
AND link.categ_id = pc.id AND pp.id IN %s)) p ORDER BY proc_id, route_id
|
||||
""", (tuple(ids), tuple(ids), ))
|
||||
product_routes = cr.fetchall()
|
||||
old_proc = False
|
||||
key = tuple()
|
||||
key_routes = {}
|
||||
proc = False
|
||||
for proc, route in product_routes:
|
||||
if not old_proc:
|
||||
old_proc = proc
|
||||
if old_proc == proc:
|
||||
key += (route,)
|
||||
else:
|
||||
if key_routes.get(key):
|
||||
key_routes[key] += [old_proc]
|
||||
else:
|
||||
key_routes[key] = [old_proc]
|
||||
old_proc = proc
|
||||
key = (route,)
|
||||
if proc: #do not forget last one as we passed through it
|
||||
if key_routes.get(key):
|
||||
key_routes[key] += [proc]
|
||||
else:
|
||||
key_routes[key] = [proc]
|
||||
return key_routes
|
||||
|
||||
|
||||
def _get_wh_loc_dict(self, cr, uid, procurements, context=None):
|
||||
wh_dict = {}
|
||||
for procurement in procurements:
|
||||
if wh_dict.get(procurement.warehouse_id.id):
|
||||
if wh_dict[procurement.warehouse_id.id].get(procurement.location_id):
|
||||
wh_dict[procurement.warehouse_id.id][procurement.location_id] += [procurement]
|
||||
else:
|
||||
wh_dict[procurement.warehouse_id.id][procurement.location_id] = [procurement]
|
||||
else:
|
||||
wh_dict[procurement.warehouse_id.id] = {}
|
||||
wh_dict[procurement.warehouse_id.id][procurement.location_id] = [procurement]
|
||||
return wh_dict
|
||||
|
||||
|
||||
def _find_suitable_rule_multi(self, cr, uid, procurements, domain = [], context=None):
|
||||
'''we try to first find a rule among the ones defined on the procurement order group and if none is found, we try on the routes defined for the product, and finally we fallback on the default behavior'''
|
||||
results_dict = {}
|
||||
pull_obj = self.pool.get('procurement.rule')
|
||||
warehouse_route_ids = []
|
||||
for procurement in procurements: #Could be replaced by one query for all route_ids
|
||||
if procurement.route_ids:
|
||||
procurement_route_ids = [x.id for x in procurement.route_ids]
|
||||
loc = procurement.location_id
|
||||
loc_domain = [('location_id.parent_left', '<=', loc.parent_left),
|
||||
('location_id.parent_right', '>=', loc.parent_left)]
|
||||
if procurement.warehouse_id:
|
||||
domain += ['|', ('warehouse_id', '=', procurement.warehouse_id.id), ('warehouse_id', '=', False)]
|
||||
res = pull_obj.search(cr, uid, loc_domain + [('route_id', 'in', procurement_route_ids)], order='route_sequence, sequence', context=context)
|
||||
if res and res[0]:
|
||||
results_dict[procurement.id] = res[0]
|
||||
|
||||
procurements_to_check = [x for x in procurements if x.id not in results_dict.keys()]
|
||||
#group by warehouse_id:
|
||||
wh_dict = self._get_wh_loc_dict(cr, uid, procurements_to_check, context=context)
|
||||
for wh in wh_dict.keys():
|
||||
warehouse_route_ids = []
|
||||
domain = []
|
||||
check_wh = False
|
||||
for loc in wh_dict[wh].keys():
|
||||
procurement = wh_dict[wh][loc][0]
|
||||
loc_domain = [('location_id.parent_left', '<=', loc.parent_left),
|
||||
('location_id.parent_right', '>=', loc.parent_left)]
|
||||
if wh and not check_wh:
|
||||
domain += ['|', ('warehouse_id', '=', procurement.warehouse_id.id), ('warehouse_id', '=', False)]
|
||||
warehouse_route_ids = [x.id for x in procurement.warehouse_id.route_ids]
|
||||
check_wh = True
|
||||
key_routes = self._get_route_group_dict(cr, uid, wh_dict[wh][loc], context=context)
|
||||
for key in key_routes.keys():
|
||||
procurements = self.browse(cr, uid, key_routes[key], context=context)
|
||||
domain = loc_domain + domain
|
||||
res = pull_obj.search(cr, uid, domain + [('route_id', 'in', list(key))], order='route_sequence, sequence', context=context)
|
||||
result = False
|
||||
if res and res[0]:
|
||||
result = res[0]
|
||||
elif warehouse_route_ids:
|
||||
res = pull_obj.search(cr, uid, domain + [('route_id', 'in', warehouse_route_ids)], order='route_sequence, sequence', context=context)
|
||||
result = res and res[0]
|
||||
if not result:
|
||||
res = pull_obj.search(cr, uid, domain + [('route_id', '=', False)], order='sequence', context=context)
|
||||
result = res and res[0]
|
||||
for proc in key_routes[key]:
|
||||
results_dict[proc] = result
|
||||
return results_dict
|
||||
|
||||
|
||||
|
||||
def _search_suitable_rule(self, cr, uid, procurement, domain, context=None):
|
||||
def _search_suitable_rule(self, cr, uid, ids, domain, context=None):
|
||||
'''we try to first find a rule among the ones defined on the procurement order group and if none is found, we try on the routes defined for the product, and finally we fallback on the default behavior'''
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
pull_obj = self.pool.get('procurement.rule')
|
||||
warehouse_route_ids = []
|
||||
if procurement.warehouse_id:
|
||||
@@ -254,22 +125,24 @@ class procurement_order(osv.osv):
|
||||
res = pull_obj.search(cr, uid, domain + [('route_id', '=', False)], order='sequence', context=context)
|
||||
return res
|
||||
|
||||
def _find_suitable_rule(self, cr, uid, procurement, context=None):
|
||||
rule_id = super(procurement_order, self)._find_suitable_rule(cr, uid, procurement, context=context)
|
||||
def _find_suitable_rule(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
rule_id = super(procurement_order, self)._find_suitable_rule(cr, uid, ids, context=context)
|
||||
if not rule_id:
|
||||
#a rule defined on 'Stock' is suitable for a procurement in 'Stock\Bin A'
|
||||
all_parent_location_ids = self._find_parent_locations(cr, uid, procurement, context=context)
|
||||
rule_id = self._search_suitable_rule(cr, uid, procurement, [('location_id', 'in', all_parent_location_ids)], context=context)
|
||||
all_parent_location_ids = procurement._find_parent_locations()
|
||||
rule_id = procurement._search_suitable_rule([('location_id', 'in', all_parent_location_ids)])
|
||||
rule_id = rule_id and rule_id[0] or False
|
||||
return rule_id
|
||||
|
||||
def _run_move_create(self, cr, uid, procurement, context=None):
|
||||
def _run_move_create(self, cr, uid, ids, context=None):
|
||||
''' Returns a dictionary of values that will be used to create a stock move from a procurement.
|
||||
This function assumes that the given procurement has a rule (action == 'move') set on it.
|
||||
|
||||
:param procurement: browse record
|
||||
:rtype: dictionary
|
||||
'''
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
newdate = (datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.rule_id.delay or 0)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
group_id = False
|
||||
if procurement.rule_id.group_propagation_option == 'propagate':
|
||||
@@ -307,17 +180,18 @@ class procurement_order(osv.osv):
|
||||
}
|
||||
return vals
|
||||
|
||||
def _run(self, cr, uid, procurement, context=None):
|
||||
def _run(self, cr, uid, ids, context=None):
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
if procurement.rule_id and procurement.rule_id.action == 'move':
|
||||
if not procurement.rule_id.location_src_id:
|
||||
self.message_post(cr, uid, [procurement.id], body=_('No source location defined!'), context=context)
|
||||
return False
|
||||
move_obj = self.pool.get('stock.move')
|
||||
move_dict = self._run_move_create(cr, uid, procurement, context=context)
|
||||
move_dict = procurement._run_move_create()
|
||||
#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)
|
||||
return True
|
||||
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
|
||||
return super(procurement_order, self)._run(cr, uid, ids, context=context)
|
||||
|
||||
def run(self, cr, uid, ids, autocommit=False, context=None):
|
||||
new_ids = [x.id for x in self.browse(cr, uid, ids, context=context) if x.state not in ('running', 'done', 'cancel')]
|
||||
@@ -338,10 +212,11 @@ class procurement_order(osv.osv):
|
||||
res = res and self.run(cr, uid, procurement_ids, autocommit=autocommit, context=context)
|
||||
return res
|
||||
|
||||
def _check(self, cr, uid, procurement, context=None):
|
||||
def _check(self, cr, uid, ids, context=None):
|
||||
''' Implement the procurement checking for rules of type 'move'. The procurement will be satisfied only if all related
|
||||
moves are done/cancel and if the requested quantity is moved.
|
||||
'''
|
||||
procurement = self.browse(cr, uid, ids[0], context=context)
|
||||
if procurement.rule_id and procurement.rule_id.action == 'move':
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
# In case Phantom BoM splits only into procurements
|
||||
@@ -421,28 +296,19 @@ class procurement_order(osv.osv):
|
||||
pass
|
||||
return {}
|
||||
|
||||
def _get_orderpoint_date_planned(self, cr, uid, orderpoint, start_date, context=None):
|
||||
days = orderpoint.lead_days or 0.0
|
||||
if orderpoint.lead_type=='purchase':
|
||||
# These days will be substracted when creating the PO
|
||||
days += orderpoint.product_id._select_seller(orderpoint.product_id).delay or 0.0
|
||||
date_planned = start_date + relativedelta(days=days)
|
||||
return date_planned.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
def _procurement_from_orderpoint_get_order(self, cr, uid, context=None):
|
||||
return 'location_id'
|
||||
|
||||
def _prepare_orderpoint_procurement(self, cr, uid, orderpoint, product_qty, context=None):
|
||||
return {
|
||||
'name': orderpoint.name,
|
||||
'date_planned': self._get_orderpoint_date_planned(cr, uid, orderpoint, datetime.today(), context=context),
|
||||
'product_id': orderpoint.product_id.id,
|
||||
'product_qty': product_qty,
|
||||
'company_id': orderpoint.company_id.id,
|
||||
'product_uom': orderpoint.product_uom.id,
|
||||
'location_id': orderpoint.location_id.id,
|
||||
'origin': orderpoint.name,
|
||||
'warehouse_id': orderpoint.warehouse_id.id,
|
||||
'orderpoint_id': orderpoint.id,
|
||||
'group_id': orderpoint.group_id.id,
|
||||
}
|
||||
def _procurement_from_orderpoint_get_grouping_key(self, cr, uid, orderpoint_ids, context=None):
|
||||
orderpoint = self.pool['stock.warehouse.orderpoint'].browse(cr, uid, orderpoint_ids[0], context=context)
|
||||
return orderpoint.location_id.id
|
||||
|
||||
def _procurement_from_orderpoint_get_groups(self, cr, uid, orderpoint_ids, context=None):
|
||||
""" Make groups for a given orderpoint; by default schedule all operations in one without date """
|
||||
return [{'to_date': False, 'procurement_values': dict()}]
|
||||
|
||||
def _procurement_from_orderpoint_post_process(self, cr, uid, orderpoint_ids, context=None):
|
||||
return True
|
||||
|
||||
def _procure_orderpoint_confirm(self, cr, uid, use_new_cursor=False, company_id=False, context=None):
|
||||
'''
|
||||
@@ -453,74 +319,83 @@ class procurement_order(osv.osv):
|
||||
'''
|
||||
if context is None:
|
||||
context = {}
|
||||
procurement_context = dict(context, procurement_autorun_defer=True)
|
||||
if use_new_cursor:
|
||||
cr = openerp.registry(cr.dbname).cursor()
|
||||
orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')
|
||||
procurement_obj = self.pool.get('procurement.order')
|
||||
product_obj = self.pool.get('product.product')
|
||||
|
||||
dom = company_id and [('company_id', '=', company_id)] or []
|
||||
orderpoint_ids = orderpoint_obj.search(cr, uid, dom, order="location_id")
|
||||
prev_ids = []
|
||||
tot_procs = []
|
||||
orderpoint_ids = orderpoint_obj.search(
|
||||
cr, uid,
|
||||
company_id and [('company_id', '=', company_id)] or [],
|
||||
order=self._procurement_from_orderpoint_get_order(cr, uid, context=context))
|
||||
procurement_ids = []
|
||||
while orderpoint_ids:
|
||||
ids = orderpoint_ids[:1000]
|
||||
del orderpoint_ids[:1000]
|
||||
product_dict = {}
|
||||
ops_dict = {}
|
||||
ops = orderpoint_obj.browse(cr, uid, ids, context=context)
|
||||
current_ids = orderpoint_ids[:1000]
|
||||
orderpoint_ids = orderpoint_ids[1000:]
|
||||
orderpoints = orderpoint_obj.browse(cr, uid, current_ids, context=context)
|
||||
|
||||
#Calculate groups that can be executed together
|
||||
for op in ops:
|
||||
key = (op.location_id.id,)
|
||||
if not product_dict.get(key):
|
||||
product_dict[key] = [op.product_id]
|
||||
ops_dict[key] = [op]
|
||||
else:
|
||||
product_dict[key] += [op.product_id]
|
||||
ops_dict[key] += [op]
|
||||
# Calculate groups that can be executed together
|
||||
location_data = defaultdict(lambda: dict(products=list(), orderpoints=list(), groups=list()))
|
||||
|
||||
for key in product_dict.keys():
|
||||
ctx = context.copy()
|
||||
ctx.update({'location': ops_dict[key][0].location_id.id})
|
||||
prod_qty = product_obj._product_available(cr, uid, [x.id for x in product_dict[key]],
|
||||
context=ctx)
|
||||
subtract_qty = orderpoint_obj.subtract_procurements_from_orderpoints(cr, uid, [x.id for x in ops_dict[key]], context=context)
|
||||
for op in ops_dict[key]:
|
||||
try:
|
||||
prods = prod_qty[op.product_id.id]['virtual_available']
|
||||
if prods is None:
|
||||
continue
|
||||
if float_compare(prods, op.product_min_qty, precision_rounding=op.product_uom.rounding) <= 0:
|
||||
qty = max(op.product_min_qty, op.product_max_qty) - prods
|
||||
reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0
|
||||
if float_compare(reste, 0.0, precision_rounding=op.product_uom.rounding) > 0:
|
||||
qty += op.qty_multiple - reste
|
||||
for orderpoint in orderpoints:
|
||||
key = self._procurement_from_orderpoint_get_grouping_key(cr, uid, [orderpoint.id], context=context)
|
||||
location_data[key]['products'] += orderpoint.product_id
|
||||
location_data[key]['orderpoints'] += orderpoint
|
||||
location_data[key]['groups'] = self._procurement_from_orderpoint_get_groups(cr, uid, [orderpoint.id], context=context)
|
||||
|
||||
if float_compare(qty, 0.0, precision_rounding=op.product_uom.rounding) < 0:
|
||||
for location_id, location_data in location_data.iteritems():
|
||||
location_orderpoints = location_data['orderpoints']
|
||||
product_context = dict(context, location=location_orderpoints[0].location_id.id)
|
||||
substract_quantity = self.pool['stock.warehouse.orderpoint'].subtract_procurements_from_orderpoints(
|
||||
cr, uid,
|
||||
[op.id for op in location_orderpoints],
|
||||
context=context)
|
||||
|
||||
for group in location_data['groups']:
|
||||
if group['to_date']:
|
||||
product_context['to_date'] = group['to_date'].strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
product_quantity = product_obj._product_available(cr, uid, [prod.id for prod in location_data['products']], context=product_context)
|
||||
for orderpoint in location_orderpoints:
|
||||
try:
|
||||
op_product_virtual = product_quantity[orderpoint.product_id.id]['virtual_available']
|
||||
if op_product_virtual is None:
|
||||
continue
|
||||
if float_compare(op_product_virtual, orderpoint.product_min_qty, precision_rounding=orderpoint.product_uom.rounding) <= 0:
|
||||
qty = max(orderpoint.product_min_qty, orderpoint.product_max_qty) - op_product_virtual
|
||||
remainder = orderpoint.qty_multiple > 0 and qty % orderpoint.qty_multiple or 0.0
|
||||
|
||||
qty -= subtract_qty[op.id]
|
||||
if float_compare(remainder, 0.0, precision_rounding=orderpoint.product_uom.rounding) > 0:
|
||||
qty += orderpoint.qty_multiple - remainder
|
||||
|
||||
qty_rounded = float_round(qty, precision_rounding=op.product_uom.rounding)
|
||||
if qty_rounded > 0:
|
||||
proc_id = procurement_obj.create(cr, uid,
|
||||
self._prepare_orderpoint_procurement(cr, uid, op, qty_rounded, context=context),
|
||||
context=dict(context, procurement_autorun_defer=True))
|
||||
tot_procs.append(proc_id)
|
||||
if float_compare(qty, 0.0, precision_rounding=orderpoint.product_uom.rounding) < 0:
|
||||
continue
|
||||
|
||||
qty -= substract_quantity[orderpoint.id]
|
||||
qty_rounded = float_round(qty, precision_rounding=orderpoint.product_uom.rounding)
|
||||
if qty_rounded > 0:
|
||||
new_procurement_id = procurement_obj.create(
|
||||
cr, uid,
|
||||
orderpoint._prepare_procurement_values(qty_rounded, **group['procurement_values']),
|
||||
context=procurement_context)
|
||||
procurement_ids.append(new_procurement_id)
|
||||
self._procurement_from_orderpoint_post_process(cr, uid, [orderpoint.id], context=context)
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
|
||||
except OperationalError:
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
except OperationalError:
|
||||
if use_new_cursor:
|
||||
orderpoint_ids.append(op.id)
|
||||
cr.rollback()
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
orderpoint_ids += orderpoint.id
|
||||
cr.rollback()
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
|
||||
try:
|
||||
tot_procs.reverse()
|
||||
self.run(cr, uid, tot_procs, context=context)
|
||||
tot_procs = []
|
||||
procurement_ids.reverse()
|
||||
self.run(cr, uid, procurement_ids, context=context)
|
||||
procurement_ids = []
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
except OperationalError:
|
||||
@@ -532,10 +407,6 @@ class procurement_order(osv.osv):
|
||||
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
if prev_ids == ids:
|
||||
break
|
||||
else:
|
||||
prev_ids = ids
|
||||
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
|
||||
+2
-13
@@ -209,12 +209,6 @@ class product_product(osv.osv):
|
||||
quants = dict((k, v) for k, v in quants.iteritems() if eval(str(v) + operator + str(value)))
|
||||
return(list(quants))
|
||||
|
||||
def _product_available_text(self, cr, uid, ids, field_names=None, arg=False, context=None):
|
||||
res = {}
|
||||
for product in self.browse(cr, uid, ids, context=context):
|
||||
res[product.id] = str(product.qty_available) + _(" On Hand")
|
||||
return res
|
||||
|
||||
def _compute_nbr_reordering_rules(self, cr, uid, ids, field_names=None, arg=None, context=None):
|
||||
res = dict.fromkeys(ids, {'nbr_reordering_rules': 0, 'reordering_min_qty': 0, 'reordering_max_qty': 0})
|
||||
product_data = self.pool['stock.warehouse.orderpoint'].read_group(cr, uid, [('product_id', 'in', ids)], ['product_id', 'product_min_qty', 'product_max_qty'], ['product_id'], context=context)
|
||||
@@ -382,12 +376,6 @@ class product_template(osv.osv):
|
||||
product_variant_ids = prod.search(cr, uid, domain, context=context)
|
||||
return [('product_variant_ids', 'in', product_variant_ids)]
|
||||
|
||||
def _product_available_text(self, cr, uid, ids, field_names=None, arg=False, context=None):
|
||||
res = {}
|
||||
for product in self.browse(cr, uid, ids, context=context):
|
||||
res[product.id] = str(product.qty_available) + _(" On Hand")
|
||||
return res
|
||||
|
||||
def _compute_nbr_reordering_rules(self, cr, uid, ids, field_names=None, arg=None, context=None):
|
||||
res = {k: {'nbr_reordering_rules': 0, 'reordering_min_qty': 0, 'reordering_max_qty': 0} for k in ids}
|
||||
product_data = self.pool['stock.warehouse.orderpoint'].read_group(cr, uid, [('product_id.product_tmpl_id', 'in', ids)], ['product_id', 'product_min_qty', 'product_max_qty'], ['product_id'], context=context)
|
||||
@@ -552,7 +540,8 @@ class product_putaway_strategy(osv.osv):
|
||||
'method': 'fixed',
|
||||
}
|
||||
|
||||
def putaway_apply(self, cr, uid, putaway_strat, product, context=None):
|
||||
def putaway_apply(self, cr, uid, ids, product, context=None):
|
||||
putaway_strat = self.browse(cr, uid, ids[0], context=context)
|
||||
if putaway_strat.method == 'fixed':
|
||||
for strat in putaway_strat.fixed_location_ids:
|
||||
categ = product.categ_id
|
||||
|
||||
@@ -159,15 +159,6 @@ class stock_config_settings(osv.osv_memory):
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
return user.company_id.id
|
||||
|
||||
def get_default_dp(self, cr, uid, fields, context=None):
|
||||
dp = self.pool.get('ir.model.data').get_object(cr, uid, 'product', 'decimal_stock_weight')
|
||||
return {'decimal_precision': dp.digits}
|
||||
|
||||
def set_default_dp(self, cr, uid, ids, context=None):
|
||||
config = self.browse(cr, uid, ids[0], context)
|
||||
dp = self.pool.get('ir.model.data').get_object(cr, uid, 'product', 'decimal_stock_weight')
|
||||
dp.write({'digits': config.decimal_precision})
|
||||
|
||||
_defaults = {
|
||||
'company_id': _default_company,
|
||||
}
|
||||
|
||||
+425
-460
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@
|
||||
<field name="model">stock.picking.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="oe_background_grey o_kanban_dashboard o_stock_kanban" create="0">
|
||||
<field name="complete_name"/>
|
||||
<field name="color"/>
|
||||
<field name="code"/>
|
||||
<field name="count_picking_ready"/>
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<button name="prepare_inventory" states="draft" string="Start Inventory" type="object" class="oe_highlight" groups="stock.group_stock_user"/>
|
||||
<button name="action_done" states="confirm" string="Validate Inventory" type="object" class="oe_highlight" groups="stock.group_stock_manager"/>
|
||||
<button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object"/>
|
||||
<button name="action_cancel_inventory" states="confirm" string="Cancel Inventory" type="object"/>
|
||||
<button name="action_cancel_draft" states="confirm" string="Cancel Inventory" type="object"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,done"/>
|
||||
</header>
|
||||
<sheet>
|
||||
@@ -600,7 +600,7 @@
|
||||
<button name="toggle_active" type="object" class="oe_stat_button" icon="fa-archive">
|
||||
<field name="active" widget="boolean_button" options='{"terminology": "archive"}'/>
|
||||
</button>
|
||||
<button name="view_all_routes_for_wh"
|
||||
<button name="action_view_all_routes"
|
||||
string="Routes"
|
||||
icon="fa-refresh"
|
||||
class="oe_stat_button"
|
||||
@@ -1008,7 +1008,7 @@
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="qty_done" invisible="1"/>
|
||||
<field name="lots_visible" invisible="1"/>
|
||||
<field name="processed_boolean"/>
|
||||
<field name="is_done"/>
|
||||
<button name="show_details" string="Modify" type="object" icon="fa-pencil"
|
||||
states="confirmed,assigned,waiting,partially_available" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
@@ -1016,7 +1016,7 @@
|
||||
<button class="oe_link oe_right" name="put_in_pack" type="object" string="↳Put in Pack" attrs="{'invisible': [('state', 'in', ('done', 'cancel'))]}" groups="stock.group_tracking_lot"/>
|
||||
</page>
|
||||
<page string="Initial Demand">
|
||||
<field name="move_lines" attrs="{'invisible': [('state', 'not in', ('draft', 'confirmed', 'waiting'))]}" options="{'reload_on_button': True}" mode="tree,kanban" context="{'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'default_picking_type_id': picking_type_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}">
|
||||
<field name="move_lines" attrs="{'readonly': [('state', 'in', ('cancel', 'partially_available', 'assigned', 'done'))]}" options="{'reload_on_button': True}" mode="tree,kanban" context="{'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'default_picking_type_id': picking_type_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}">
|
||||
<kanban class="o_kanban_mobile">
|
||||
<field name="product_id"/>
|
||||
<field name="availability"/>
|
||||
@@ -1044,7 +1044,6 @@
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
<field name="move_lines_related" attrs="{'invisible': [('state', 'in', ('draft', 'confirmed', 'waiting', 'done'))]}" readonly="1" context="{'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'default_picking_type_id': picking_type_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}"/>
|
||||
<field name="pack_operation_exist" invisible="1"/>
|
||||
<field name="note" placeholder="Add an internal note..." class="oe_inline"/>
|
||||
</page>
|
||||
@@ -2265,7 +2264,7 @@
|
||||
<separator string="Contained Packages"/>
|
||||
<field name="children_ids">
|
||||
<tree string="Contained Packages">
|
||||
<field name="complete_name"/>
|
||||
<field name="display_name"/>
|
||||
<field name="packaging_id"/>
|
||||
<field name="location_id"/>
|
||||
</tree>
|
||||
@@ -2284,7 +2283,7 @@
|
||||
<field eval="10" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Package">
|
||||
<field name="complete_name"/>
|
||||
<field name="display_name"/>
|
||||
<field name="packaging_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="company_id"/>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.tools import float_compare
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
|
||||
class stock_immediate_transfer(models.TransientModel):
|
||||
_name = 'stock.immediate.transfer'
|
||||
_description = 'Immediate Transfer'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="view_immediate_transfer" model="ir.ui.view">
|
||||
<field name="name">view_immediate_transfer</field>
|
||||
<field name="name">stock.immediate.transfer.view.form</field>
|
||||
<field name="model">stock.immediate.transfer</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Immediate transfer?">
|
||||
@@ -13,7 +13,7 @@
|
||||
</group>
|
||||
<footer>
|
||||
<button name="process" string="_Apply" type="object" class="btn-primary"/>
|
||||
<button string="_Cancel" class="btn-default" special="cancel" />
|
||||
<button string="Cancel" class="btn-default" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -16,13 +16,14 @@ class stock_inventory(osv.osv):
|
||||
'accounting_date': fields.date('Force Accounting Date', help="Choose the accounting date at which you want to value the stock moves created by the inventory instead of the default one (the inventory end date)"),
|
||||
}
|
||||
|
||||
def post_inventory(self, cr, uid, inv, context=None):
|
||||
def post_inventory(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
ctx = context.copy()
|
||||
inv = self.browse(cr, uid, ids, context=context)[0]
|
||||
if inv.accounting_date:
|
||||
ctx['force_period_date'] = inv.accounting_date
|
||||
return super(stock_inventory, self).post_inventory(cr, uid, inv, context=ctx)
|
||||
return super(stock_inventory, self).post_inventory(cr, uid, ids, context=ctx)
|
||||
|
||||
|
||||
class account_invoice_line(osv.osv):
|
||||
@@ -161,20 +162,21 @@ class stock_quant(osv.osv):
|
||||
if quant.product_id.cost_method == 'real' and quant.location_id.usage != 'internal':
|
||||
self.pool.get('stock.move')._store_average_cost_price(cr, uid, move, context=context)
|
||||
|
||||
def _account_entry_move(self, cr, uid, quants, move, context=None):
|
||||
def _account_entry_move(self, cr, uid, ids, move, context=None):
|
||||
"""
|
||||
Accounting Valuation Entries
|
||||
|
||||
quants: browse record list of Quants to create accounting valuation entries for. Unempty and all quants are supposed to have the same location id (thay already moved in)
|
||||
move: Move to use. browse record
|
||||
"""
|
||||
quants = self.browse(cr, uid, ids, context=context)
|
||||
if context is None:
|
||||
context = {}
|
||||
location_obj = self.pool.get('stock.location')
|
||||
location_from = move.location_id
|
||||
location_to = quants[0].location_id
|
||||
company_from = location_obj._location_owner(cr, uid, location_from, context=context)
|
||||
company_to = location_obj._location_owner(cr, uid, location_to, context=context)
|
||||
company_from = location_from and (location_from.usage == 'internal') and location_from.company_id or False
|
||||
company_to = location_to and (location_to.usage == 'internal') and location_to.company_id or False
|
||||
|
||||
if move.product_id.valuation != 'real_time':
|
||||
return False
|
||||
@@ -214,10 +216,10 @@ class stock_quant(osv.osv):
|
||||
else:
|
||||
self._create_account_move_line(cr, uid, quants, move, acc_valuation, acc_dest, journal_id, context=ctx)
|
||||
|
||||
def _quant_create(self, cr, uid, qty, move, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, force_location_from=False, force_location_to=False, context=None):
|
||||
def _quant_create_from_move(self, cr, uid, qty, move, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, force_location_from=False, force_location_to=False, context=None):
|
||||
quant_obj = self.pool.get('stock.quant')
|
||||
quant = super(stock_quant, self)._quant_create(cr, uid, qty, move, lot_id=lot_id, owner_id=owner_id, src_package_id=src_package_id, dest_package_id=dest_package_id, force_location_from=force_location_from, force_location_to=force_location_to, context=context)
|
||||
self._account_entry_move(cr, uid, [quant], move, context)
|
||||
quant = super(stock_quant, self)._quant_create_from_move(cr, uid, qty, move, lot_id=lot_id, owner_id=owner_id, src_package_id=src_package_id, dest_package_id=dest_package_id, force_location_from=force_location_from, force_location_to=force_location_to, context=context)
|
||||
quant._account_entry_move(move)
|
||||
if move.product_id.valuation == 'real_time':
|
||||
# If the precision required for the variable quant cost is larger than the accounting
|
||||
# precision, inconsistencies between the stock valuation and the accounting entries
|
||||
@@ -237,14 +239,14 @@ class stock_quant(osv.osv):
|
||||
and float_compare(quant.qty, 2.0, precision_rounding=quant.product_id.uom_id.rounding) >= 0:
|
||||
qty = quant.qty
|
||||
cost = quant.cost
|
||||
quant_correct = quant_obj._quant_split(cr, uid, quant, quant.qty - 1.0, context=context)
|
||||
quant_correct = quant._quant_split(quant.qty - 1.0)
|
||||
cost_correct += (qty * cost) - (qty * cost_rounded)
|
||||
quant_obj.write(cr, SUPERUSER_ID, [quant.id], {'cost': cost_rounded}, context=context)
|
||||
quant_obj.write(cr, SUPERUSER_ID, [quant_correct.id], {'cost': cost_correct}, context=context)
|
||||
return quant
|
||||
|
||||
def move_quants_write(self, cr, uid, quants, move, location_dest_id, dest_package_id, lot_id=False, entire_pack=False, context=None):
|
||||
res = super(stock_quant, self).move_quants_write(cr, uid, quants, move, location_dest_id, dest_package_id, lot_id=lot_id, entire_pack=entire_pack, context=context)
|
||||
def _quant_update_from_move(self, cr, uid, quants, move, location_dest_id, dest_package_id, lot_id=False, entire_pack=False, context=None):
|
||||
res = super(stock_quant, self)._quant_update_from_move(cr, uid, quants, move, location_dest_id, dest_package_id, lot_id=lot_id, entire_pack=entire_pack, context=context)
|
||||
self._account_entry_move(cr, uid, quants, move, context=context)
|
||||
return res
|
||||
|
||||
|
||||
@@ -80,23 +80,6 @@ class procurement_order(osv.osv):
|
||||
res.update({'date_planned': procurement.next_delivery_date})
|
||||
return res
|
||||
|
||||
def _prepare_orderpoint_procurement(self, cr, uid, orderpoint, product_qty, date=False, purchase_date = False, group=False, context=None):
|
||||
return {
|
||||
'name': orderpoint.name,
|
||||
'date_planned': date or self._get_orderpoint_date_planned(cr, uid, orderpoint, datetime.today(), context=context),
|
||||
'next_delivery_date': date,
|
||||
'next_purchase_date': purchase_date,
|
||||
'product_id': orderpoint.product_id.id,
|
||||
'product_qty': product_qty,
|
||||
'company_id': orderpoint.company_id.id,
|
||||
'product_uom': orderpoint.product_uom.id,
|
||||
'location_id': orderpoint.location_id.id,
|
||||
'origin': orderpoint.name,
|
||||
'warehouse_id': orderpoint.warehouse_id.id,
|
||||
'orderpoint_id': orderpoint.id,
|
||||
'group_id': group or orderpoint.group_id.id,
|
||||
}
|
||||
|
||||
def _get_previous_dates(self, cr, uid, orderpoint, start_date = False, context=None):
|
||||
"""
|
||||
Date should be given in utc
|
||||
@@ -197,6 +180,7 @@ class procurement_order(osv.osv):
|
||||
new_date = datetime.strptime(orderpoint.last_execution_date, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
else:
|
||||
new_date = datetime.utcnow()
|
||||
# TDE note: I bet accessing interval[2] will crash, no ? this code seems very louche
|
||||
intervals = calendar_obj._schedule_days(cr, uid, orderpoint.purchase_calendar_id.id, 1, new_date, compute_leaves=True, context=context)
|
||||
for interval in intervals:
|
||||
# If last execution date, interval should start after it in order not to execute the same orderpoint twice
|
||||
@@ -209,119 +193,28 @@ class procurement_order(osv.osv):
|
||||
return [(now_date, None)]
|
||||
return res_intervals
|
||||
|
||||
def _procure_orderpoint_confirm(self, cr, uid, use_new_cursor=False, company_id=False, context=None):
|
||||
'''
|
||||
Create procurement based on Orderpoint
|
||||
def _procurement_from_orderpoint_get_order(self, cr, uid, context=None):
|
||||
return 'location_id, purchase_calendar_id, calendar_id'
|
||||
|
||||
:param bool use_new_cursor: if set, use a dedicated cursor and auto-commit after processing each procurement.
|
||||
This is appropriate for batch jobs only.
|
||||
'''
|
||||
if context is None:
|
||||
context = {}
|
||||
if use_new_cursor:
|
||||
cr = openerp.registry(cr.dbname).cursor()
|
||||
orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')
|
||||
procurement_obj = self.pool.get('procurement.order')
|
||||
product_obj = self.pool.get('product.product')
|
||||
dom = company_id and [('company_id', '=', company_id)] or []
|
||||
orderpoint_ids = orderpoint_obj.search(cr, uid, dom, order="location_id, purchase_calendar_id, calendar_id")
|
||||
prev_ids = []
|
||||
tot_procs = []
|
||||
while orderpoint_ids:
|
||||
ids = orderpoint_ids[:1000]
|
||||
del orderpoint_ids[:1000]
|
||||
dates_dict = {}
|
||||
product_dict = {}
|
||||
ops_dict = {}
|
||||
ops = orderpoint_obj.browse(cr, uid, ids, context=context)
|
||||
def _procurement_from_orderpoint_get_grouping_key(self, cr, uid, orderpoint_ids, context=None):
|
||||
orderpoint = self.pool['stock.warehouse.orderpoint'].browse(cr, uid, orderpoint_ids[0], context=context)
|
||||
return (orderpoint.location_id.id, orderpoint.purchase_calendar_id.id, orderpoint.calendar_id.id)
|
||||
|
||||
#Calculate groups that can be executed together
|
||||
for op in ops:
|
||||
key = (op.location_id.id, op.purchase_calendar_id.id, op.calendar_id.id)
|
||||
res_groups=[]
|
||||
if not dates_dict.get(key):
|
||||
date_groups = self._get_group(cr, uid, op, context=context)
|
||||
for date, group in date_groups:
|
||||
if op.calendar_id and op.calendar_id.attendance_ids:
|
||||
date1, date2 = self._get_next_dates(cr, uid, op, date, group, context=context)
|
||||
res_groups += [(group, date1, date2, date)] #date1/date2 as deliveries and date as purchase confirmation date
|
||||
else:
|
||||
res_groups += [(group, date, False, date)]
|
||||
dates_dict[key] = res_groups
|
||||
product_dict[key] = [op.product_id]
|
||||
ops_dict[key] = [op]
|
||||
else:
|
||||
product_dict[key] += [op.product_id]
|
||||
ops_dict[key] += [op]
|
||||
|
||||
for key in product_dict.keys():
|
||||
for res_group in dates_dict[key]:
|
||||
ctx = context.copy()
|
||||
ctx.update({'location': ops_dict[key][0].location_id.id})
|
||||
if res_group[2]:
|
||||
ctx.update({'to_date': res_group[2].strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
|
||||
prod_qty = product_obj._product_available(cr, uid, [x.id for x in product_dict[key]],
|
||||
context=ctx)
|
||||
group = res_group[0]
|
||||
date = res_group[1]
|
||||
subtract_qty = orderpoint_obj.subtract_procurements_from_orderpoints(cr, uid, [x.id for x in ops_dict[key]], context=context)
|
||||
first_op = True
|
||||
ndelivery = date
|
||||
npurchase = res_group[3]
|
||||
for op in ops_dict[key]:
|
||||
try:
|
||||
prods = prod_qty[op.product_id.id]['virtual_available']
|
||||
if prods is None:
|
||||
continue
|
||||
|
||||
if float_compare(prods, op.product_min_qty, precision_rounding=op.product_uom.rounding) < 0:
|
||||
qty = max(op.product_min_qty, op.product_max_qty) - prods
|
||||
reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0
|
||||
if float_compare(reste, 0.0, precision_rounding=op.product_uom.rounding) > 0:
|
||||
qty += op.qty_multiple - reste
|
||||
|
||||
if float_compare(qty, 0.0, precision_rounding=op.product_uom.rounding) <= 0:
|
||||
continue
|
||||
|
||||
qty -= subtract_qty[op.id]
|
||||
|
||||
qty_rounded = float_round(qty, precision_rounding=op.product_uom.rounding)
|
||||
if qty_rounded > 0:
|
||||
proc_id = procurement_obj.create(cr, uid,
|
||||
self._prepare_orderpoint_procurement(cr, uid, op, qty_rounded, date=ndelivery, purchase_date=npurchase, group=group, context=context),
|
||||
context=context)
|
||||
tot_procs.append(proc_id)
|
||||
orderpoint_obj.write(cr, uid, [op.id], {'last_execution_date': datetime.utcnow().strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
except OperationalError:
|
||||
if use_new_cursor:
|
||||
orderpoint_ids.append(op.id)
|
||||
cr.rollback()
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
try:
|
||||
tot_procs.reverse()
|
||||
self.run(cr, uid, tot_procs, context=context)
|
||||
tot_procs = []
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
except OperationalError:
|
||||
if use_new_cursor:
|
||||
cr.rollback()
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
if prev_ids == ids:
|
||||
break
|
||||
def _procurement_from_orderpoint_get_groups(self, cr, uid, orderpoint_ids, context=None):
|
||||
orderpoint = self.pool['stock.warehouse.orderpoint'].browse(cr, uid, orderpoint_ids[0], context=context)
|
||||
res_groups = []
|
||||
date_groups = self._get_group(cr, uid, orderpoint, context=context)
|
||||
for date, group in date_groups:
|
||||
if orderpoint.calendar_id and orderpoint.calendar_id.attendance_ids:
|
||||
date1, date2 = self._get_next_dates(cr, uid, orderpoint, date, group, context=context)
|
||||
res_groups += [{'to_date': date2, 'procurement_values': {'group': group, 'date': date1, 'purchase_date': date}}] # date1/date2 as deliveries and date as purchase confirmation date
|
||||
else:
|
||||
prev_ids = ids
|
||||
res_groups += [{'to_date': False, 'procurement_values': {'group': group, 'date': date, 'purchase_date': date}}]
|
||||
return res_groups
|
||||
|
||||
if use_new_cursor:
|
||||
cr.commit()
|
||||
cr.close()
|
||||
return {}
|
||||
def _procurement_from_orderpoint_post_process(self, cr, uid, orderpoint_ids, context=None):
|
||||
self.pool['stock.warehouse.orderpoint'].write(
|
||||
cr, uid, orderpoint_ids, {
|
||||
'last_execution_date': datetime.utcnow().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
}, context=context)
|
||||
return super(procurement_order, self)._procurement_from_orderpoint_post_process(cr, uid, orderpoint_ids, context=context)
|
||||
|
||||
@@ -9,3 +9,10 @@ class stock_warehouse_orderpoint(osv.osv):
|
||||
'purchase_calendar_id': fields.many2one('resource.calendar', 'Purchase Calendar'),
|
||||
'last_execution_date': fields.datetime('Last Execution Date', readonly=True),
|
||||
}
|
||||
|
||||
def _prepare_procurement_values(self, cr, uid, ids, product_qty, date=False, purchase_date=False, group=False, context=None):
|
||||
res = super(stock_warehouse_orderpoint, self)._prepare_procurement_values(cr, uid, ids, product_qty, date=date, group=group, context=context)
|
||||
res.update({
|
||||
'next_delivery_date': date,
|
||||
'next_purchase_date': purchase_date})
|
||||
return res
|
||||
|
||||
@@ -232,7 +232,7 @@ class stock_landed_cost(osv.osv):
|
||||
# Search for existing quant of quantity = 1.0 to avoid creating a new one
|
||||
quant_correct = quants.filtered(lambda r: float_compare(r.qty, 1.0, precision_rounding=quants[0].product_id.uom_id.rounding) == 0)
|
||||
if not quant_correct:
|
||||
quant_correct = quant_obj._quant_split(cr, uid, quants[0], quants[0].qty - 1.0, context=context)
|
||||
quant_correct = quants[0]._quant_split(quants[0].qty - 1.0)
|
||||
else:
|
||||
quant_correct = quant_correct[0]
|
||||
quants = quants - quant_correct
|
||||
|
||||
Reference in New Issue
Block a user