Merge pull request #2292 from odoo-dev/8.0-wmsstaging8-jco

8.0 wmsstaging8 jco
This commit is contained in:
Josse Colpaert
2014-09-12 14:24:29 +02:00
25 changed files with 256 additions and 139 deletions
@@ -198,8 +198,8 @@
product_uom_qty: 1.0
product_uom: product.product_uom_unit
location_dest_id: stock.stock_location_customers
invoice_state: 2binvoiced
move_type: direct
invoice_state: 2binvoiced
picking_type_id: stock.picking_type_out
-
I need to check the availability of the product, So I make my picking order for processing later.
@@ -200,7 +200,7 @@
product_id: product_fifo_anglo_saxon
product_uom_qty: 1.0
location_dest_id: stock.stock_location_customers
invoice_state: 2binvoiced
invoice_state: 2binvoiced
move_type: direct
picking_type_id: stock.picking_type_out
-
+48 -27
View File
@@ -230,7 +230,7 @@ class mrp_bom(osv.osv):
}
_order = "sequence"
def _bom_find(self, cr, uid, product_uom, product_tmpl_id=None, product_id=None, properties=None):
def _bom_find(self, cr, uid, product_uom, product_tmpl_id=None, product_id=None, properties=None, context=None):
""" Finds BoM for particular product and product uom.
@param product_tmpl_id: Selected product.
@param product_uom: Unit of measure of a product.
@@ -241,7 +241,7 @@ class mrp_bom(osv.osv):
properties = []
if product_id:
if not product_tmpl_id:
product_tmpl_id = self.pool['product.product'].browse(cr, uid, product_id).product_tmpl_id.id
product_tmpl_id = self.pool['product.product'].browse(cr, uid, product_id, context=context).product_tmpl_id.id
domain = [
'|',
('product_id', '=', product_id),
@@ -255,21 +255,21 @@ class mrp_bom(osv.osv):
# neither product nor template, makes no sense to search
return False
if product_uom:
domain += [('product_uom','=',product_uom)]
domain += [('product_uom','=',product_uom)]
domain = domain + [ '|', ('date_start', '=', False), ('date_start', '<=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)),
'|', ('date_stop', '=', False), ('date_stop', '>=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT))]
# order to prioritize bom with product_id over the one without
ids = self.search(cr, uid, domain, order='product_id')
for bom in self.pool.get('mrp.bom').browse(cr, uid, ids):
if not set(map(int,bom.property_ids or [])) - set(properties or []):
if not set(map(int, bom.property_ids or [])) - set(properties or []):
return bom.id
return False
def _bom_explode(self, cr, uid, bom, product, factor, properties=None, level=0, routing_id=False, previous_products=None, master_bom=None):
def _bom_explode(self, cr, uid, bom, product, factor, properties=None, level=0, routing_id=False, previous_products=None, master_bom=None, context=None):
""" Finds Products and Work Centers for related BoM for manufacturing order.
@param bom: BoM of particular product template.
@param product: Select a particular variant of the BoM. If False use BoM without variants.
@param factor: Factor of product UoM.
@param factor: Factor represents the quantity, but in UoM of the BoM, taking into account the numbers produced by the BoM
@param properties: A List of properties Ids.
@param level: Depth level to find BoM lines starts from 10.
@param previous_products: List of product previously use by bom explore to avoid recursion
@@ -277,6 +277,7 @@ class mrp_bom(osv.osv):
@return: result: List of dictionaries containing product details.
result2: List of dictionaries containing Work Center details.
"""
uom_obj = self.pool.get("product.uom")
routing_obj = self.pool.get('mrp.routing')
all_prod = [] + (previous_products or [])
master_bom = master_bom or bom
@@ -312,9 +313,6 @@ class mrp_bom(osv.osv):
if bom_line_id.date_start and bom_line_id.date_start > time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) or \
bom_line_id.date_stop and bom_line_id.date_stop > time.strftime(DEFAULT_SERVER_DATETIME_FORMAT):
continue
# check properties
if set(map(int,bom_line_id.property_ids or [])) - set(properties or []):
continue
# all bom_line_id variant values must be in the product
if bom_line_id.attribute_value_ids:
if not product or (set(map(int,bom_line_id.attribute_value_ids or [])) - set(map(int,product.attribute_value_ids))):
@@ -322,27 +320,32 @@ class mrp_bom(osv.osv):
if bom_line_id.product_id.id in all_prod:
raise osv.except_osv(_('Invalid Action!'), _('BoM "%s" contains a BoM line with a product recursion: "%s".') % (master_bom.name,bom_line_id.product_id.name_get()[0][1]))
all_prod.append(bom_line_id.product_id.id)
if bom_line_id.type != "phantom":
quantity = _factor(bom_line_id.product_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding)
bom_id = self._bom_find(cr, uid, bom_line_id.product_uom.id, product_id=bom_line_id.product_id.id, properties=properties, context=context)
#If BoM should not behave like PhantoM, just add the product, otherwise explode further
if bom_line_id.type != "phantom" and (not bom_id or self.browse(cr, uid, bom_id, context=context).type != "phantom"):
result.append({
'name': bom_line_id.product_id.name,
'product_id': bom_line_id.product_id.id,
'product_qty': _factor(bom_line_id.product_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding),
'product_qty': quantity,
'product_uom': bom_line_id.product_uom.id,
'product_uos_qty': bom_line_id.product_uos and bom_line_id.product_uos_qty * factor or False,
'product_uos_qty': bom_line_id.product_uos and _factor(bom_line_id.product_uos_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding) or False,
'product_uos': bom_line_id.product_uos and bom_line_id.product_uos.id or False,
})
elif bom_id:
all_prod.append(bom_line_id.product_id.id)
bom2 = self.browse(cr, uid, bom_id, context=context)
# We need to convert to units/UoM of chosen BoM
factor2 = uom_obj._compute_qty(cr, uid, bom_line_id.product_uom.id, quantity, bom2.product_uom.id)
quantity2 = factor2 / bom2.product_qty
res = self._bom_explode(cr, uid, bom2, bom_line_id.product_id, quantity2,
properties=properties, level=level + 10, previous_products=all_prod, master_bom=master_bom, context=context)
result = result + res[0]
result2 = result2 + res[1]
else:
bom_id = self._bom_find(cr, uid, bom_line_id.product_uom.id, product_id=bom_line_id.product_id.id, properties=properties)
if bom_id:
bom2 = self.browse(cr, uid, bom_id)
res = self._bom_explode(cr, uid, bom2, bom_line_id.product_id, factor,
properties=properties, level=level + 10, previous_products=all_prod, master_bom=master_bom)
result = result + res[0]
result2 = result2 + res[1]
else:
raise osv.except_osv(_('Invalid Action!'), _('BoM "%s" contains a phantom BoM line but the product "%s" don\'t have any BoM defined.') % (master_bom.name,bom_line_id.product_id.name_get()[0][1]))
raise osv.except_osv(_('Invalid Action!'), _('BoM "%s" contains a phantom BoM line but the product "%s" don\'t have any BoM defined.') % (master_bom.name,bom_line_id.product_id.name_get()[0][1]))
return result, result2
@@ -642,7 +645,7 @@ class mrp_production(osv.osv):
}}
bom_obj = self.pool.get('mrp.bom')
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
bom_id = bom_obj._bom_find(cr, uid, product.uom_id and product.uom_id.id, product_id=product.id, properties=[])
bom_id = bom_obj._bom_find(cr, uid, product.uom_id and product.uom_id.id, product_id=product.id, properties=[], context=context)
routing_id = False
if bom_id:
bom_point = bom_obj.browse(cr, uid, bom_id, context=context)
@@ -691,7 +694,7 @@ class mrp_production(osv.osv):
bom_point = production.bom_id
bom_id = production.bom_id.id
if not bom_point:
bom_id = bom_obj._bom_find(cr, uid, production.product_uom.id, product_id=production.product_id.id, properties=properties)
bom_id = bom_obj._bom_find(cr, uid, production.product_uom.id, product_id=production.product_id.id, properties=properties, context=context)
if bom_id:
bom_point = bom_obj.browse(cr, uid, bom_id)
routing_id = bom_point.routing_id.id or False
@@ -703,7 +706,7 @@ class mrp_production(osv.osv):
# get components and workcenter_lines from BoM structure
factor = uom_obj._compute_qty(cr, uid, production.product_uom.id, production.product_qty, bom_point.product_uom.id)
# product_lines, workcenter_lines
results, results2 = bom_obj._bom_explode(cr, uid, bom_point, production.product_id, factor / bom_point.product_qty, properties, routing_id=production.routing_id.id)
results, results2 = bom_obj._bom_explode(cr, uid, bom_point, production.product_id, factor / bom_point.product_qty, properties, routing_id=production.routing_id.id, context=context)
# reset product_lines in production order
for line in results:
line['production_id'] = production.id
@@ -1063,15 +1066,32 @@ class mrp_production(osv.osv):
'''
When the routing gives a different location than the raw material location of the production order,
we should create an extra move from the raw material location to the location of the routing, which
precedes the consumption line (chained)
precedes the consumption line (chained). The picking type depends on the warehouse in which this happens
and the type of locations.
'''
loc_obj = self.pool.get("stock.location")
stock_move = self.pool.get('stock.move')
type_obj = self.pool.get('stock.picking.type')
# Need to search for a picking type
move = stock_move.browse(cr, uid, move_id, context=context)
code = stock_move.get_code_from_locs(cr, uid, move, context=context)
if code == 'outgoing':
check_loc_id = source_location_id
else:
check_loc_id = dest_location_id
check_loc = loc_obj.browse(cr, uid, check_loc_id, context=context)
wh = loc_obj.get_warehouse(cr, uid, check_loc, context=context)
domain = [('code', '=', code)]
if wh:
domain += [('warehouse_id', '=', wh)]
types = type_obj.search(cr, uid, domain, context=context)
move = stock_move.copy(cr, uid, move_id, default = {
'location_id': source_location_id,
'location_dest_id': dest_location_id,
'procure_method': self._get_raw_material_procure_method(cr, uid, product, context=context),
'raw_material_production_id': False,
'move_dest_id': move_id,
'picking_type_id': types and types[0] or False,
}, context=context)
return move
@@ -1109,6 +1129,7 @@ class mrp_production(osv.osv):
if prev_move:
prev_move = self._create_previous_move(cr, uid, move_id, product, prod_location_id, source_location_id, context=context)
stock_move.action_confirm(cr, uid, [prev_move], context=context)
return move_id
def _make_production_consume_line(self, cr, uid, line, context=None):
+2 -2
View File
@@ -63,7 +63,7 @@ class procurement_order(osv.osv):
for procurement in self.browse(cr, uid, ids, context=context):
properties = [x.id for x in procurement.property_ids]
bom_id = self.pool.get('mrp.bom')._bom_find(cr, uid, procurement.product_uom.id,
product_id=procurement.product_id.id, properties=properties)
product_id=procurement.product_id.id, properties=properties, context=context)
if not bom_id:
return False
return True
@@ -85,7 +85,7 @@ class procurement_order(osv.osv):
else:
properties = [x.id for x in procurement.property_ids]
bom_id = bom_obj._bom_find(cr, uid, procurement.product_uom.id,
product_id=procurement.product_id.id, properties=properties)
product_id=procurement.product_id.id, properties=properties, context=context)
bom = bom_obj.browse(cr, uid, bom_id, context=context)
routing_id = bom.routing_id.id
+2 -2
View File
@@ -59,10 +59,10 @@ class bom_structure(report_sxw.rml_parse):
return children
class report_lunchorder(osv.AbstractModel):
class report_mrpbomstructure(osv.AbstractModel):
_name = 'report.mrp.report_mrpbomstructure'
_inherit = 'report.abstract_report'
_template = 'mpr.report_mrpbomstructure'
_template = 'mrp.report_mrpbomstructure'
_wrapped_report_class = bom_structure
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+2 -2
View File
@@ -144,7 +144,7 @@ class report_custom(report_rml):
for product in product_pool.browse(cr, uid, ids, context=context):
product_uom_name = to_xml(product.uom_id.name)
bom_id = bom_pool._bom_find(cr, uid, product.uom_id.id, product_id=product.id)
bom_id = bom_pool._bom_find(cr, uid, product.uom_id.id, product_id=product.id, context=context)
title = "<title>%s</title>" %(_("Cost Structure"))
title += "<title>%s</title>" % (to_xml(product.name))
xml += "<lines style='header'>" + title + prod_header + "</lines>"
@@ -168,7 +168,7 @@ class report_custom(report_rml):
else:
bom = bom_pool.browse(cr, uid, bom_id, context=context)
factor = number * product.uom_id.factor / bom.product_uom.factor
sub_boms = bom_pool._bom_explode(cr, uid, bom, product, factor / bom.product_qty)
sub_boms = bom_pool._bom_explode(cr, uid, bom, product, factor / bom.product_qty, context=context)
total = 0
total_strd = 0
parent_bom = {
+1
View File
@@ -52,6 +52,7 @@ class mrp_config_settings(osv.osv_memory):
'group_mrp_properties': fields.boolean("Allow several bill of materials per products using properties",
implied_group='product.group_mrp_properties',
help="""The selection of the right Bill of Material to use will depend on the properties specified on the sales order and the Bill of Material."""),
#FIXME: Should be removed as module product_manufacturer has been removed
'module_product_manufacturer': fields.boolean("Define manufacturers on products ",
help='This allows you to define the following for a product:\n'
'* Manufacturer\n'
-4
View File
@@ -54,10 +54,6 @@
<group >
<label for="id" string="Products"/>
<div>
<div>
<field name="module_product_manufacturer" class="oe_inline"/>
<label for="module_product_manufacturer"/>
</div>
<div>
<field name="group_mrp_properties" class="oe_inline"/>
<label for="group_mrp_properties" />
+4 -3
View File
@@ -67,13 +67,14 @@ class StockMove(osv.osv):
move_obj = self.pool.get('stock.move')
prod_obj = self.pool.get("product.product")
proc_obj = self.pool.get("procurement.order")
uom_obj = self.pool.get("product.uom")
to_explode_again_ids = []
processed_ids = []
bis = self._check_phantom_bom(cr, uid, move, context=context)
if bis:
factor = move.product_qty
bom_point = bom_obj.browse(cr, SUPERUSER_ID, bis[0], context=context)
res = bom_obj._bom_explode(cr, SUPERUSER_ID, bom_point, move.product_id, factor, [])
factor = uom_obj._compute_qty(cr, SUPERUSER_ID, move.product_uom.id, move.product_uom_qty, bom_point.product_uom.id) / bom_point.product_qty
res = bom_obj._bom_explode(cr, SUPERUSER_ID, bom_point, move.product_id, factor, [], context=context)
state = 'confirmed'
if move.state == 'assigned':
@@ -91,7 +92,7 @@ class StockMove(osv.osv):
'state': state,
'name': line['name'],
'procurement_id': move.procurement_id.id,
'split_from': move.id, #Needed in order to keep purchase connection, but will be removed by unlink
'split_from': move.id, #Needed in order to keep sale connection, but will be removed by unlink
}
mid = move_obj.copy(cr, uid, move.id, default=valdef, context=context)
to_explode_again_ids.append(mid)
+2 -2
View File
@@ -78,7 +78,7 @@ class change_production_qty(osv.osv_memory):
bom_point = prod.bom_id
bom_id = prod.bom_id.id
if not bom_point:
bom_id = bom_obj._bom_find(cr, uid, prod.product_uom.id, product_id=prod.product_id.id)
bom_id = bom_obj._bom_find(cr, uid, prod.product_uom.id, product_id=prod.product_id.id, context=context)
if not bom_id:
raise osv.except_osv(_('Error!'), _("Cannot find bill of material for this product."))
prod_obj.write(cr, uid, [prod.id], {'bom_id': bom_id})
@@ -89,7 +89,7 @@ class change_production_qty(osv.osv_memory):
factor = prod.product_qty * prod.product_uom.factor / bom_point.product_uom.factor
product_details, workcenter_details = \
bom_obj._bom_explode(cr, uid, bom_point, prod.product_id, factor / bom_point.product_qty, [])
bom_obj._bom_explode(cr, uid, bom_point, prod.product_id, factor / bom_point.product_qty, [], context=context)
for r in product_details:
if r['product_id'] == move.product_id.id:
move_obj.write(cr, uid, [move.id], {'product_uom_qty': r['product_qty']})
-38
View File
@@ -1190,45 +1190,7 @@ class product_supplierinfo(osv.osv):
'delay': 1,
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'product.supplierinfo', context=c),
}
def price_get(self, cr, uid, supplier_ids, product_id, product_qty=1, context=None):
"""
Calculate price from supplier pricelist.
@param supplier_ids: Ids of res.partner object.
@param product_id: Id of product.
@param product_qty: specify quantity to purchase.
"""
if type(supplier_ids) in (int,long,):
supplier_ids = [supplier_ids]
res = {}
product_pool = self.pool.get('product.product')
partner_pool = self.pool.get('res.partner')
pricelist_pool = self.pool.get('product.pricelist')
currency_pool = self.pool.get('res.currency')
currency_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
# Compute price from standard price of product
product_price = product_pool.price_get(cr, uid, [product_id], 'standard_price', context=context)[product_id]
product = product_pool.browse(cr, uid, product_id, context=context)
for supplier in partner_pool.browse(cr, uid, supplier_ids, context=context):
price = product_price
# Compute price from Purchase pricelist of supplier
pricelist_id = supplier.property_product_pricelist_purchase.id
if pricelist_id:
price = pricelist_pool.price_get(cr, uid, [pricelist_id], product_id, product_qty, context=context).setdefault(pricelist_id, 0)
price = currency_pool.compute(cr, uid, pricelist_pool.browse(cr, uid, pricelist_id).currency_id.id, currency_id, price)
# Compute price from supplier pricelist which are in Supplier Information
supplier_info_ids = self.search(cr, uid, [('name','=',supplier.id),('product_tmpl_id','=',product.product_tmpl_id.id)])
if supplier_info_ids:
cr.execute('SELECT * ' \
'FROM pricelist_partnerinfo ' \
'WHERE suppinfo_id IN %s' \
'AND min_quantity <= %s ' \
'ORDER BY min_quantity DESC LIMIT 1', (tuple(supplier_info_ids),product_qty,))
res2 = cr.dictfetchone()
if res2:
price = res2['price']
res[supplier.id] = price
return res
_order = 'sequence'
+8 -2
View File
@@ -672,6 +672,10 @@ class purchase_order(osv.osv):
return True
return False
def wkf_action_cancel(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
self.set_order_line_status(cr, uid, ids, 'cancel', context=context)
def action_cancel(self, cr, uid, ids, context=None):
for purchase in self.browse(cr, uid, ids, context=context):
for pick in purchase.picking_ids:
@@ -727,7 +731,7 @@ class purchase_order(osv.osv):
'origin': order.name,
'route_ids': order.picking_type_id.warehouse_id and [(6, 0, [x.id for x in order.picking_type_id.warehouse_id.route_ids])] or [],
'warehouse_id':order.picking_type_id.warehouse_id.id,
'invoice_state': order.invoice_method == 'picking' and '2binvoiced' or 'none'
'invoice_state': order.invoice_method == 'picking' and '2binvoiced' or 'none',
}
diff_quantity = order_line.product_qty
@@ -741,6 +745,7 @@ class purchase_order(osv.osv):
'group_id': procurement.group_id.id or group_id, #move group is same as group of procurements if it exists, otherwise take another group
'procurement_id': procurement.id,
'invoice_state': procurement.rule_id.invoice_state or (procurement.location_id and procurement.location_id.usage == 'customer' and procurement.invoice_state=='picking' and '2binvoiced') or (order.invoice_method == 'picking' and '2binvoiced') or 'none', #dropship case takes from sale
'propagate': procurement.rule_id.propagate,
})
diff_quantity -= min(procurement_qty, diff_quantity)
res.append(tmp)
@@ -821,7 +826,8 @@ class purchase_order(osv.osv):
picking_vals = {
'picking_type_id': order.picking_type_id.id,
'partner_id': order.dest_address_id.id or order.partner_id.id,
'date': max([l.date_planned for l in order.order_line])
'date': max([l.date_planned for l in order.order_line]),
'origin': order.name
}
picking_id = self.pool.get('stock.picking').create(cr, uid, picking_vals, context=context)
self._create_stock_moves(cr, uid, order, order.order_line, picking_id, context=context)
+1 -1
View File
@@ -37,7 +37,7 @@
<field name="name">cancel</field>
<field name="kind">function</field>
<field name="flow_stop">True</field>
<field name="action">action_cancel()</field>
<field name="action">wkf_action_cancel()</field>
</record>
<record id="act_except_invoice" model="workflow.activity">
<field name="wkf_id" ref="purchase_order"/>
+31 -3
View File
@@ -53,7 +53,6 @@ class stock_move(osv.osv):
default['purchase_line_id'] = False
return super(stock_move, self).copy(cr, uid, id, default, context)
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
invoice_line_id = super(stock_move, self)._create_invoice_line_from_vals(cr, uid, move, invoice_line_vals, context=context)
if move.purchase_line_id:
@@ -69,9 +68,16 @@ class stock_move(osv.osv):
def _get_master_data(self, cr, uid, move, company, context=None):
if move.purchase_line_id:
purchase_order = move.purchase_line_id.order_id
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.pricelist_id.currency_id.id
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
else:
partner = move.picking_id and move.picking_id.partner_id or False
code = self.get_code_from_locs(cr, uid, move, context=context)
if partner and partner.property_product_pricelist_purchase and code == 'incoming':
currency = partner.property_product_pricelist_purchase.currency_id.id
return partner, uid, currency
return super(stock_move, self)._get_master_data(cr, uid, move, company, context=context)
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
res = super(stock_move, self)._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
if move.purchase_line_id:
@@ -80,6 +86,29 @@ class stock_move(osv.osv):
res['price_unit'] = purchase_line.price_unit
return res
def attribute_price(self, cr, uid, move, context=None):
"""
Attribute price to move, important in inter-company moves or receipts with only one partner
"""
code = self.get_code_from_locs(cr, uid, move, context=context)
if not move.purchase_line_id and code == 'incoming' and not move.price_unit:
partner = move.picking_id and move.picking_id.partner_id or False
price = False
# If partner given, search price in its purchase pricelist
if partner and partner.property_product_pricelist_purchase:
pricelist_obj = self.pool.get("product.pricelist")
pricelist = partner.property_product_pricelist.id
price = pricelist_obj.price_get(cr, uid, [pricelist],
move.product_id.id, move.product_uom_qty, partner, {
'uom': move.product_uom.id,
'date': move.date,
})[pricelist]
if price:
return self.write(cr, uid, [move.id], {'price_unit': price}, context=context)
super(stock_move, self).attribute_price(cr, uid, move, context=context)
class stock_picking(osv.osv):
_inherit = 'stock.picking'
@@ -137,7 +166,6 @@ class stock_warehouse(osv.osv):
'route_id': buy_route_id,
'action': 'buy',
'picking_type_id': warehouse.in_type_id.id,
'propagate': False,
'warehouse_id': warehouse.id,
}
+10
View File
@@ -90,3 +90,13 @@ class sale_order_line(osv.osv):
_columns = {
'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]}),
}
class stock_move(osv.osv):
_inherit = 'stock.move'
def _prepare_procurement_from_move(self, cr, uid, move, context=None):
res = super(stock_move, self)._prepare_procurement_from_move(cr, uid, move, context=context)
if res and move.procurement_id and move.procurement_id.property_ids:
res['property_ids'] = [(6, 0, [x.id for x in move.procurement_id.property_ids])]
return res
+13
View File
@@ -16,5 +16,18 @@
</field>
</record>
<record id="view_order_form_inherit_mrp" model="ir.ui.view">
<field name="name">sale.order.form.sale.stock.mrp</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='address_allotment_id']" position="after">
<field name="property_ids" widget="many2many_tags"
groups="sale.group_mrp_properties"/>
</xpath>
</field>
</record>
</data>
</openerp>
+2 -1
View File
@@ -288,8 +288,9 @@ class sale_order_line(osv.osv):
product_uom_obj = self.pool.get('product.uom')
product_obj = self.pool.get('product.product')
warning = {}
#UoM False due to hack which makes sure uom changes price, ... in product_id_change
res = self.product_id_change(cr, uid, ids, pricelist, product, qty=qty,
uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
uom=False, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
if not product:
-4
View File
@@ -62,10 +62,6 @@
<field name="delay" class="oe_inline"/> days
</div>
</xpath>
<!--<xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='address_allotment_id']" position="after">
<field name="property_ids" widget="many2many_tags"
groups="sale.group_mrp_properties"/>
</xpath>-->
<xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='tax_id']" position="before">
<field name="product_packaging" context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}" on_change="product_packaging_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, parent.partner_id, product_packaging, True, context)" domain="[('product_tmpl_id','=',product_id)]" groups="product.group_stock_packaging" />
</xpath>
+12 -8
View File
@@ -10,9 +10,10 @@
<tree position="attributes">
<attribute name="colors">{'red':virtual_available&lt;0, 'blue':virtual_available&gt;=0 and state in ('draft', 'end', 'obsolete'), 'black':virtual_available&gt;=0 and state not in ('draft', 'end', 'obsolete')}</attribute>
</tree>
<tree position="inside">
<field name="virtual_available" invisible="1"/>
</tree>
<field name="price" position="after">
<field name="qty_available"/>
<field name="virtual_available"/>
</field>
</field>
</record>
@@ -24,9 +25,10 @@
<tree position="attributes">
<attribute name="colors">{'red':virtual_available&lt;0, 'blue':virtual_available&gt;=0 and state in ('draft', 'end', 'obsolete'), 'black':virtual_available&gt;=0 and state not in ('draft', 'end', 'obsolete')}</attribute>
</tree>
<tree position="inside">
<field name="virtual_available" invisible="1"/>
</tree>
<field name="uom_id" position="after">
<field name="qty_available"/>
<field name="virtual_available"/>
</field>
</field>
</record>
@@ -82,8 +84,10 @@
<separator/>
<filter name="real_stock_available" string="Available Products" domain="[('qty_available','&gt;',0)]"/>
<filter name="virtual_stock_available" string="Forecast Available Products" domain="[('virtual_available','&gt;',0)]"/>
<filter name="real_stock_negative" string="Exhausted Stock" domain="[('qty_available','&lt;=',0)]"/>
<filter name="virtual_stock_negative" string="Forecast Exhausted Stock" domain="[('virtual_available','&lt;=',0)]"/>
<filter name="real_stock_exhausted" string="Exhausted Stock" domain="[('qty_available','&lt;=',0)]"/>
<filter name="virtual_stock_exhausted" string="Forecast Exhausted Stock" domain="[('virtual_available','&lt;=',0)]"/>
<filter name="real_stock_negative" string="Negative Stock" domain="[('qty_available','&lt;',0)]"/>
<filter name="virtual_stock_negative" string="Forecast Negative Stock" domain="[('virtual_available','&lt;',0)]"/>
</field>
<filter name="consumable" position="before">
<filter string="Products" icon="terp-accessories-archiver" domain="[('type','=','product')]" help="Stockable products"/>
+51 -18
View File
@@ -189,6 +189,16 @@ class stock_location(osv.osv):
return self._default_removal_strategy(cr, uid, context=context)
def get_warehouse(self, cr, uid, location, context=None):
"""
Returns warehouse id of warehouse that contains location
:param location: browse record (stock.location)
"""
wh_obj = self.pool.get("stock.warehouse")
whs = wh_obj.search(cr, uid, [('view_location_id.parent_left', '<=', location.parent_left),
('view_location_id.parent_right', '>=', location.parent_left)], context=context)
return whs and whs[0] or False
#----------------------------------------------------------
# Routes
#----------------------------------------------------------
@@ -1525,12 +1535,6 @@ class stock_move(osv.osv):
res.append((line.id, name))
return res
def create(self, cr, uid, vals, context=None):
if vals.get('product_id') and not vals.get('price_unit'):
prod_obj = self.pool.get('product.product')
vals['price_unit'] = prod_obj.browse(cr, uid, vals['product_id'], context=context).standard_price
return super(stock_move, self).create(cr, uid, vals, context=context)
def _quantity_normalize(self, cr, uid, ids, name, args, context=None):
uom_obj = self.pool.get('product.uom')
res = {}
@@ -2020,6 +2024,13 @@ class stock_move(osv.osv):
date_expected = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
return {'value': {'date': date_expected}}
def attribute_price(self, cr, uid, move, context=None):
"""
Attribute price to move, important in inter-company moves or receipts with only one partner
"""
if not move.price_unit:
price = move.product_id.standard_price
self.write(cr, uid, [move.id], {'price_unit': price})
def action_confirm(self, cr, uid, ids, context=None):
""" Confirms stock move or put it in waiting if it's linked to another move.
@@ -2033,6 +2044,7 @@ class stock_move(osv.osv):
}
to_assign = {}
for move in self.browse(cr, uid, ids, context=context):
self.attribute_price(cr, uid, move, context=context)
state = 'confirmed'
#if the move is preceeded, then it's waiting (if preceeding move is done, then action_assign has been called already and its state is already available)
if move.move_orig_ids:
@@ -2430,6 +2442,21 @@ class stock_move(osv.osv):
return self.action_confirm(cr, uid, [new_move], context=context)[0]
def get_code_from_locs(self, cr, uid, move, context=None):
"""
Returns the code the picking type should have. This can easily be used
to check if a move is internal or not
"""
code = 'internal'
src_loc = move.location_id
dest_loc = 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
class stock_inventory(osv.osv):
_name = "stock.inventory"
_description = "Inventory"
@@ -3457,6 +3484,7 @@ class stock_warehouse(osv.osv):
'limit': 20
}
class stock_location_path(osv.osv):
_name = "stock.location.path"
_description = "Pushed Flows"
@@ -3503,6 +3531,21 @@ class stock_location_path(osv.osv):
'active': True,
}
def _prepare_push_apply(self, cr, uid, rule, move, context=None):
newdate = (datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta.relativedelta(days=rule.delay or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
return {
'location_id': move.location_dest_id.id,
'location_dest_id': rule.location_dest_id.id,
'date': newdate,
'company_id': rule.company_id and rule.company_id.id or False,
'date_expected': newdate,
'picking_id': False,
'picking_type_id': rule.picking_type_id and rule.picking_type_id.id or False,
'propagate': rule.propagate,
'push_rule_id': rule.id,
'warehouse_id': rule.warehouse_id and rule.warehouse_id.id or False,
}
def _apply(self, cr, uid, rule, move, context=None):
move_obj = self.pool.get('stock.move')
newdate = (datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta.relativedelta(days=rule.delay or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
@@ -3519,18 +3562,8 @@ class stock_location_path(osv.osv):
#call again push_apply to see if a next step is defined
move_obj._push_apply(cr, uid, [move], context=context)
else:
move_id = move_obj.copy(cr, uid, move.id, {
'location_id': move.location_dest_id.id,
'location_dest_id': rule.location_dest_id.id,
'date': newdate,
'company_id': rule.company_id and rule.company_id.id or False,
'date_expected': newdate,
'picking_id': False,
'picking_type_id': rule.picking_type_id and rule.picking_type_id.id or False,
'propagate': rule.propagate,
'push_rule_id': rule.id,
'warehouse_id': rule.warehouse_id and rule.warehouse_id.id or False,
})
vals = self._prepare_push_apply(cr, uid, rule, move, context=context)
move_id = move_obj.copy(cr, uid, move.id, vals, context=context)
move_obj.write(cr, uid, [move.id], {
'move_dest_id': move_id,
})
+13
View File
@@ -306,6 +306,14 @@
<field name="res_model">stock.quant</field>
</record>
<act_window
context="{'location': active_id, 'search_default_real_stock_available': 1, 'search_default_virtual_stock_available': 1,
'search_default_virtual_stock_negative': 1, 'search_default_real_stock_negative': 1}"
id="act_product_location_open"
name="Products"
res_model="product.product"
src_model="stock.location"/>
<record id="view_location_form" model="ir.ui.view">
<field name="name">stock.location.form</field>
<field name="model">stock.location</field>
@@ -316,6 +324,11 @@
class="oe_stat_button"
icon="fa-building-o" name="%(location_open_quants)d" type="action"
context="{'search_default_internal_loc': 1}"/>
<button string="Products"
class="oe_stat_button"
icon="fa-filter" name="%(act_product_location_open)d" type="action"
context="{'location_id': active_id}"
/>
</div>
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
+32 -6
View File
@@ -33,6 +33,11 @@ class stock_location_path(osv.osv):
'invoice_state': '',
}
def _prepare_push_apply(self, cr, uid, rule, move, context=None):
res = super(stock_location_path, self)._prepare_push_apply(cr, uid, rule, move, context=context)
res['invoice_state'] = rule.invoice_state or 'none'
return res
#----------------------------------------------------------
# Procurement Rule
#----------------------------------------------------------
@@ -91,7 +96,13 @@ class stock_move(osv.osv):
def _get_master_data(self, cr, uid, move, company, context=None):
''' returns a tuple (browse_record(res.partner), ID(res.users), ID(res.currency)'''
return move.picking_id.partner_id, uid, company.currency_id.id
currency = company.currency_id.id
partner = move.picking_id and move.picking_id.partner_id
if partner:
code = self.get_code_from_locs(cr, uid, move, context=context)
if partner.property_product_pricelist and code == 'outgoing':
currency = partner.property_product_pricelist.currency_id.id
return partner, uid, currency
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
return self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context)
@@ -105,10 +116,19 @@ class stock_move(osv.osv):
if context is None:
context = {}
if type in ('in_invoice', 'in_refund'):
# Take the user company and pricetype
product = move_line.product_id.with_context(currency_id=move_line.company_id.currency_id.id)
amount_unit = product.price_get('standard_price')[move_line.product_id.id]
return amount_unit
return move_line.price_unit
else:
# If partner given, search price in its sale pricelist
if move_line.partner_id and move_line.partner_id.property_product_pricelist:
pricelist_obj = self.pool.get("product.pricelist")
pricelist = move_line.partner_id.property_product_pricelist.id
price = pricelist_obj.price_get(cr, uid, [pricelist],
move_line.product_id.id, move_line.product_uom_qty, move_line.partner_id.id, {
'uom': move_line.product_uom.id,
'date': move_line.date,
})[pricelist]
if price:
return price
return move_line.product_id.list_price
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
@@ -167,13 +187,19 @@ class stock_picking(osv.osv):
res.append(move.picking_id.id)
return res
def _set_inv_state(self, cr, uid, picking_id, name, value, arg, context=None):
pick = self.browse(cr, uid, picking_id, context=context)
moves = [x.id for x in pick.move_lines]
move_obj= self.pool.get("stock.move")
move_obj.write(cr, uid, moves, {'invoice_state': pick.invoice_state})
_columns = {
'invoice_state': fields.function(__get_invoice_state, type='selection', selection=[
("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable")
], string="Invoice Control", required=True,
fnct_inv = _set_inv_state,
store={
'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['state'], 10),
'stock.move': (__get_picking_move, ['picking_id', 'invoice_state'], 10),
@@ -82,5 +82,15 @@
</xpath>
</field>
</record>
<record model="ir.ui.view" id="view_move_picking_from_stockaccount_inherit">
<field name="name">stock.move.form.invoice_state</field>
<field name="model">stock.move</field>
<field name="inherit_id" ref="stock.view_move_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='date_expected']" position="after">
<field name="invoice_state" groups="account.group_account_invoice"/>
</xpath>
</field>
</record>
</data>
</openerp>
@@ -13,7 +13,7 @@
product_uom_qty: 3.0
product_uom: product.product_uom_unit
location_dest_id: stock.stock_location_customers
invoice_state: 2binvoiced
invoice_state: 2binvoiced
move_type: direct
picking_type_id: stock.picking_type_out
-
@@ -184,21 +184,17 @@ class stock_landed_cost(osv.osv):
total_weight = 0.0
total_volume = 0.0
total_line = 0.0
for line in cost.cost_lines:
vals = self.get_valuation_lines(cr, uid, [cost.id], picking_ids=picking_ids, context=context)
for v in vals:
vals = self.get_valuation_lines(cr, uid, [cost.id], picking_ids=picking_ids, context=context)
for v in vals:
for line in cost.cost_lines:
v.update({'cost_id': cost.id, 'cost_line_id': line.id})
self.pool.get('stock.valuation.adjustment.lines').create(cr, uid, v, context=context)
if line.split_method == 'by_quantity':
total_qty += v.get('quantity', 0.0)
elif line.split_method == 'by_current_cost_price':
total_cost += v.get('former_cost', 0.0)
elif line.split_method == 'by_weight':
total_weight += v.get('weight', 0.0)
elif line.split_method == 'by_volume':
total_volume += v.get('volume', 0.0)
else:
total_line += 1
total_qty += v.get('quantity', 0.0)
total_cost += v.get('former_cost', 0.0)
total_weight += v.get('weight', 0.0)
total_volume += v.get('volume', 0.0)
total_line += 1
for line in cost.cost_lines:
for valuation in cost.valuation_adjustment_lines:
value = 0.0