Merge pull request #2021 from odoo-dev/8.0-wmsbomtasks-jco

8.0 wmsbomtasks jco
This commit is contained in:
Josse Colpaert
2014-09-03 21:13:44 +02:00
25 changed files with 278 additions and 86 deletions
+41 -9
View File
@@ -198,9 +198,9 @@ class mrp_bom(osv.osv):
'type': fields.selection([('normal', 'Normal'), ('phantom', 'Set')], 'BoM Type', required=True,
help= "Set: When processing a sales order for this product, the delivery order will contain the raw materials, instead of the finished product."),
'position': fields.char('Internal Reference', help="Reference to a position in an external plan."),
'product_tmpl_id': fields.many2one('product.template', 'Product', required=True),
'product_tmpl_id': fields.many2one('product.template', 'Product', domain="[('type', '!=', 'service')]", required=True),
'product_id': fields.many2one('product.product', 'Product Variant',
domain="[('product_tmpl_id','=',product_tmpl_id)]",
domain="['&', ('product_tmpl_id','=',product_tmpl_id), ('type','!=', 'service')]",
help="If a product variant is defined the BOM is available only for this product."),
'bom_line_ids': fields.one2many('mrp.bom.line', 'bom_id', 'BoM Lines', copy=True),
'product_qty': fields.float('Product Quantity', required=True, digits_compute=dp.get_precision('Product Unit of Measure')),
@@ -509,7 +509,7 @@ class mrp_production(osv.osv):
for production in self.browse(cr, uid, ids, context=context):
res[production.id] = True
states = [x.state != 'assigned' for x in production.move_lines if x]
if any(states) or len(states) == 0:
if any(states) or len(states) == 0: #When no moves, ready_production will be False, but test_ready will pass
res[production.id] = False
return res
@@ -527,7 +527,8 @@ class mrp_production(osv.osv):
'priority': fields.selection([('0', 'Not urgent'), ('1', 'Normal'), ('2', 'Urgent'), ('3', 'Very Urgent')], 'Priority',
select=True, readonly=True, states=dict.fromkeys(['draft', 'confirmed'], [('readonly', False)])),
'product_id': fields.many2one('product.product', 'Product', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'product_id': fields.many2one('product.product', 'Product', required=True, readonly=True, states={'draft': [('readonly', False)]},
domain=[('type','!=','service')]),
'product_qty': fields.float('Product Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True, readonly=True, states={'draft': [('readonly', False)]}),
'product_uom': fields.many2one('product.uom', 'Product Unit of Measure', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'product_uos_qty': fields.float('Product UoS Quantity', readonly=True, states={'draft': [('readonly', False)]}),
@@ -831,6 +832,8 @@ class mrp_production(osv.osv):
dicts = {}
# Find product qty to be consumed and consume it
for scheduled in production.product_lines:
if scheduled.product_id.type == 'service':
continue
product_id = scheduled.product_id.id
consumed_qty = consumed_data.get(product_id, 0.0)
@@ -1018,11 +1021,12 @@ class mrp_production(osv.osv):
return res
def test_ready(self, cr, uid, ids):
res = False
res = True
for production in self.browse(cr, uid, ids):
if production.ready_production:
res = True
if production.move_lines and not production.ready_production:
res = False
return res
def _make_production_produce_line(self, cr, uid, production, context=None):
@@ -1115,6 +1119,26 @@ class mrp_production(osv.osv):
def _make_production_consume_line(self, cr, uid, line, context=None):
return self._make_consume_line_from_data(cr, uid, line.production_id, line.product_id, line.product_uom.id, line.product_qty, line.product_uos.id, line.product_uos_qty, context=context)
def _make_service_procurement(self, cr, uid, line, context=None):
prod_obj = self.pool.get('product.product')
if prod_obj.need_procurement(cr, uid, [line.product_id.id], context=context):
vals = {
'name': line.production_id.name,
'origin': line.production_id.name,
'company_id': line.production_id.company_id.id,
'date_planned': line.production_id.date_planned,
'product_id': line.product_id.id,
'product_qty': line.product_qty,
'product_uom': line.product_uom.id,
'product_uos_qty': line.product_uos_qty,
'product_uos': line.product_uos.id,
}
proc_obj = self.pool.get("procurement.order")
proc = proc_obj.create(cr, uid, vals, context=context)
proc_obj.run(cr, uid, [proc], context=context)
def action_confirm(self, cr, uid, ids, context=None):
""" Confirms production order.
@return: Newly generated Shipment Id.
@@ -1126,9 +1150,11 @@ class mrp_production(osv.osv):
stock_moves = []
for line in production.product_lines:
stock_move_id = self._make_production_consume_line(cr, uid, line, context=context)
if stock_move_id:
if line.product_id.type != 'service':
stock_move_id = self._make_production_consume_line(cr, uid, line, context=context)
stock_moves.append(stock_move_id)
else:
self._make_service_procurement(cr, uid, line, context=context)
if stock_moves:
self.pool.get('stock.move').action_confirm(cr, uid, stock_moves, context=context)
production.write({'state': 'confirmed'}, context=context)
@@ -1138,9 +1164,12 @@ class mrp_production(osv.osv):
"""
Checks the availability on the consume lines of the production order
"""
from openerp import workflow
move_obj = self.pool.get("stock.move")
for production in self.browse(cr, uid, ids, context=context):
move_obj.action_assign(cr, uid, [x.id for x in production.move_lines], context=context)
if self.pool.get('mrp.production').test_ready(cr, uid, [production.id]):
workflow.trg_validate(uid, 'mrp.production', production.id, 'moves_ready', cr)
def force_production(self, cr, uid, ids, *args):
@@ -1148,9 +1177,12 @@ class mrp_production(osv.osv):
@param *args: Arguments
@return: True
"""
from openerp import workflow
move_obj = self.pool.get('stock.move')
for order in self.browse(cr, uid, ids):
move_obj.force_assign(cr, uid, [x.id for x in order.move_lines])
if self.pool.get('mrp.production').test_ready(cr, uid, [order.id]):
workflow.trg_validate(uid, 'mrp.production', order.id, 'moves_ready', cr)
return True
-1
View File
@@ -349,7 +349,6 @@
<group>
<field name="product_tmpl_id" on_change="onchange_product_tmpl_id(product_tmpl_id, product_qty, context)"/>
<field name="product_id"/>
<field name="product_uom" class="oe_inline" on_change="onchange_uom(product_tmpl_id, product_uom)" groups="product.group_uom"/>
<label for="product_qty" string="Quantity"/>
<div>
<field name="product_qty" class="oe_inline" on_change="onchange_product_tmpl_id(product_tmpl_id, product_qty, context)"/>
+1 -3
View File
@@ -56,9 +56,7 @@
<record id="prod_trans_picking_ready" model="workflow.transition">
<field name="act_from" ref="prod_act_confirmed"/>
<field name="act_to" ref="prod_act_ready"/>
<field name="trigger_model">stock.move</field>
<field name="trigger_expr_id">consume_lines_get()</field>
<field name="condition">test_ready()</field>
<field name="signal">moves_ready</field>
</record>
<record id="prod_trans_ready_in_production" model="workflow.transition">
<field name="act_from" ref="prod_act_ready"/>
+58 -21
View File
@@ -65,6 +65,8 @@ class StockMove(osv.osv):
"""
bom_obj = self.pool.get('mrp.bom')
move_obj = self.pool.get('stock.move')
prod_obj = self.pool.get("product.product")
proc_obj = self.pool.get("procurement.order")
to_explode_again_ids = []
processed_ids = []
bis = self._check_phantom_bom(cr, uid, move, context=context)
@@ -72,33 +74,65 @@ class StockMove(osv.osv):
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, [])
state = 'confirmed'
if move.state == 'assigned':
state = 'assigned'
for line in res[0]:
valdef = {
'picking_id': move.picking_id.id if move.picking_id else False,
'product_id': line['product_id'],
'product_uom': line['product_uom'],
'product_uom_qty': line['product_qty'],
'product_uos': line['product_uos'],
'product_uos_qty': line['product_uos_qty'],
'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
}
mid = move_obj.copy(cr, uid, move.id, default=valdef)
to_explode_again_ids.append(mid)
product = prod_obj.browse(cr, uid, line['product_id'], context=context)
if product.type != 'service':
valdef = {
'picking_id': move.picking_id.id if move.picking_id else False,
'product_id': line['product_id'],
'product_uom': line['product_uom'],
'product_uom_qty': line['product_qty'],
'product_uos': line['product_uos'],
'product_uos_qty': line['product_uos_qty'],
'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
}
mid = move_obj.copy(cr, uid, move.id, default=valdef, context=context)
to_explode_again_ids.append(mid)
else:
if prod_obj.need_procurement(cr, uid, [product.id], context=context):
valdef = {
'name': move.rule_id and move.rule_id.name or "/",
'origin': move.origin,
'company_id': move.company_id and move.company_id.id or False,
'date_planned': move.date,
'product_id': line['product_id'],
'product_qty': line['product_qty'],
'product_uom': line['product_uom'],
'product_uos_qty': line['product_uos_qty'],
'product_uos': line['product_uos'],
'group_id': move.group_id.id,
'priority': move.priority,
'partner_dest_id': move.partner_id.id,
}
if move.procurement_id:
proc = proc_obj.copy(cr, uid, move.procurement_id.id, default=valdef, context=context)
else:
proc = proc_obj.create(cr, uid, valdef, context=context)
proc_obj.run(cr, uid, [proc], context=context) #could be omitted
#delete the move with original product which is not relevant anymore
move_obj.unlink(cr, SUPERUSER_ID, [move.id], context=context)
#check if new moves needs to be exploded
if to_explode_again_ids:
for new_move in self.browse(cr, uid, to_explode_again_ids, context=context):
processed_ids.extend(self._action_explode(cr, uid, new_move, context=context))
#return list of newly created move or the move id otherwise
return processed_ids or [move.id]
if not move.split_from and move.procurement_id:
# Check if procurements have been made to wait for
moves = move.procurement_id.move_ids
if len(moves) == 1:
proc_obj.write(cr, uid, [move.procurement_id.id], {'state': 'done'}, context=context)
#delete the move with original product which is not relevant anymore
move_obj.unlink(cr, SUPERUSER_ID, [move.id], context=context)
#return list of newly created move or the move id otherwise, unless there is no move anymore
return processed_ids or (not bis and [move.id]) or []
def action_confirm(self, cr, uid, ids, context=None):
move_ids = []
@@ -194,9 +228,12 @@ class StockMove(osv.osv):
ids = [ids]
res = super(StockMove, self).write(cr, uid, ids, vals, context=context)
from openerp import workflow
for move in self.browse(cr, uid, ids, context=context):
if move.raw_material_production_id and move.raw_material_production_id.state == 'confirmed':
workflow.trg_trigger(uid, 'stock.move', move.id, cr)
if vals.get('state') == 'assigned':
moves = self.browse(cr, uid, ids, context=context)
orders = list(set([x.raw_material_production_id.id for x in moves if x.raw_material_production_id and x.raw_material_production_id.state == 'confirmed']))
for order_id in orders:
if self.pool.get('mrp.production').test_ready(cr, uid, [order_id]):
workflow.trg_validate(uid, 'mrp.production', order_id, 'moves_ready', cr)
return res
class stock_warehouse(osv.osv):
+8
View File
@@ -764,6 +764,9 @@ class product_template(osv.osv):
return super(product_template, self).name_get(cr, user, ids, context)
class product_product(osv.osv):
_name = "product.product"
_description = "Product"
@@ -1089,6 +1092,11 @@ class product_product(osv.osv):
return super(product_product, self).create(cr, uid, vals, context=ctx)
def need_procurement(self, cr, uid, ids, context=None):
return False
class product_packaging(osv.osv):
_name = "product.packaging"
_description = "Packaging"
+15 -3
View File
@@ -225,11 +225,11 @@ FaceTime HD Camera, 1.2 MP Photos</field>
<!-- -->
<record id="product_product_5" model="product.product">
<record id="product_product_5b" model="product.product">
<field name="name">Bose Mini Bluetooth Speaker</field>
<field name="categ_id" ref="accessories"/>
<field name="standard_price">600.0</field>
<field name="list_price">147.0</field>
<field name="standard_price">140.0</field>
<field name="list_price">247.0</field>
<field name="type">consu</field>
<field name="uom_id" ref="product_uom_unit"/>
<field name="uom_po_id" ref="product_uom_unit"/>
@@ -239,6 +239,18 @@ FaceTime HD Camera, 1.2 MP Photos</field>
</record>
<record id="product_product_5" model="product.product">
<field name="name">PC Assemble + Custom (PC on Demand) </field>
<field name="categ_id" ref="accessories"/>
<field name="standard_price">600.0</field>
<field name="list_price">147.0</field>
<field name="type">consu</field>
<field name="uom_id" ref="product_uom_unit"/>
<field name="uom_po_id" ref="product_uom_unit"/>
<field name="description">Custom computer assembled on order based on customer's requirement.</field>
<field name="default_code">B3423</field>
</record>
<record id="product_product_6" model="product.product">
<field name="name">iPad Mini</field>
<field name="categ_id" ref="ipad"/>
+4
View File
@@ -23,6 +23,10 @@
</record>
<record id="product_product_5" model="product.product">
<field name="image" type="base64" file="product/static/img/product_product_5-image.jpg"/>
</record>
<record id="product_product_5b" model="product.product">
<field name="image" type="base64" file="product/static/img/product_product_5-image.png"/>
</record>
+1 -1
View File
@@ -740,7 +740,7 @@ class purchase_order(osv.osv):
'move_dest_id': procurement.move_dest_id.id, #move destination is same as procurement destination
'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) or (order.invoice_method == 'picking' and '2binvoiced') or 'none', #dropship case takes from sale
'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
})
diff_quantity -= min(procurement_qty, diff_quantity)
res.append(tmp)
+1 -1
View File
@@ -82,7 +82,7 @@ class stock_move(osv.osv):
class stock_picking(osv.osv):
_inherit = 'stock.picking'
def _get_to_invoice(self, cr, uid, ids, name, args, context=None):
res = {}
for picking in self.browse(cr, uid, ids, context=context):
+5 -1
View File
@@ -815,6 +815,10 @@ class sale_order_line(osv.osv):
def need_procurement(self, cr, uid, ids, context=None):
#when sale is installed only, there is no need to create procurements, that's only
#further installed modules (sale_service, sale_stock) that will change this.
prod_obj = self.pool.get('product.product')
for line in self.browse(cr, uid, ids, context=context):
if prod_obj.need_procurement(cr, uid, [line.product_id.id], context=context):
return True
return False
def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
@@ -1251,7 +1255,7 @@ class procurement_order(osv.osv):
from openerp import workflow
if vals.get('state') in ['done', 'cancel', 'exception']:
for proc in self.browse(cr, uid, ids, context=context):
if proc.sale_line_id and proc.sale_line_id.order_id and proc.move_ids:
if proc.sale_line_id and proc.sale_line_id.order_id:
order_id = proc.sale_line_id.order_id.id
if self.pool.get('sale.order').test_procurements_done(cr, uid, [order_id], context=context):
workflow.trg_validate(uid, 'sale.order', order_id, 'ship_end', cr)
-13
View File
@@ -69,19 +69,6 @@ class mrp_production(osv.osv):
res[production.id] = move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.client_order_ref or False
return res
def _hook_create_post_procurement(self, cr, uid, production, procurement_id, context=None):
def get_parent_move(move):
if move.move_dest_id:
return get_parent_move(move.move_dest_id)
return move
res = super(mrp_production, self)._hook_create_post_procurement(cr, uid, production, procurement_id, context)
if production.move_prod_id:
parent_move_line = get_parent_move(production.move_prod_id)
if parent_move_line and parent_move_line.sale_line_id:
self.pool.get('procurement.order').write(cr, uid, procurement_id, {'sale_line_id': parent_move_line.sale_line_id.id})
return res
_columns = {
'sale_name': fields.function(_ref_calc, multi='sale_name', type='char', string='Sale Name', help='Indicate the name of sales order.'),
'sale_ref': fields.function(_ref_calc, multi='sale_name', type='char', string='Sale Reference', help='Indicate the Customer Reference from sales order.'),
+10 -12
View File
@@ -27,7 +27,6 @@ class procurement_order(osv.osv):
_inherit = "procurement.order"
_columns = {
'task_id': fields.many2one('project.task', 'Task', copy=False),
'sale_line_id': fields.many2one('sale.order.line', 'Sales order line', copy=False)
}
def _is_procurement_task(self, cr, uid, procurement, context=None):
@@ -81,7 +80,7 @@ class procurement_order(osv.osv):
'date_deadline': procurement.date_planned,
'planned_hours': planned_hours,
'remaining_hours': planned_hours,
'partner_id': procurement.sale_line_id and procurement.sale_line_id.order_id.partner_id.id or False,
'partner_id': procurement.sale_line_id and procurement.sale_line_id.order_id.partner_id.id or procurement.partner_dest_id.id,
'user_id': procurement.product_id.product_manager.id,
'procurement_id': procurement.id,
'description': procurement.name + '\n',
@@ -139,23 +138,22 @@ class project_task(osv.osv):
self._validate_subflows(cr, uid, ids, context=context)
return res
class product_product(osv.osv):
class product_template(osv.osv):
_inherit = "product.template"
_columns = {
'project_id': fields.many2one('project.project', 'Project', ondelete='set null',),
'auto_create_task': fields.boolean('Create Task Automatically', help="Thick this option if you want to create a task automatically each time this product is sold"),
}
class sale_order_line(osv.osv):
_inherit = 'sale.order.line'
class product_product(osv.osv):
_inherit = "product.product"
def need_procurement(self, cr, uid, ids, context=None):
#when sale is installed alone, there is no need to create procurements, but with sale_service
#we must create a procurement for each service that has the auto_create_task boolean set to True.
for line in self.browse(cr, uid, ids, context=context):
if line.product_id and line.product_id.type == 'service' and line.product_id.auto_create_task:
for product in self.browse(cr, uid, ids, context=context):
if product.type == 'service' and product.auto_create_task:
return True
return super(sale_order_line, self).need_procurement(cr, uid, ids, context=context)
return super(product_product, self).need_procurement(cr, uid, ids, context=context)
+22 -7
View File
@@ -202,16 +202,20 @@ class sale_order(osv.osv):
return False
class product_product(osv.osv):
_inherit = 'product.product'
def need_procurement(self, cr, uid, ids, context=None):
#when sale/product is installed alone, there is no need to create procurements, but with sale_stock
#we must create a procurement for each product that is not a service.
for product in self.browse(cr, uid, ids, context=context):
if product.type != 'service':
return True
return super(product_product, self).need_procurement(cr, uid, ids, context=context)
class sale_order_line(osv.osv):
_inherit = 'sale.order.line'
def need_procurement(self, cr, uid, ids, context=None):
#when sale is installed alone, there is no need to create procurements, but with sale_stock
#we must create a procurement for each product that is not a service.
for line in self.browse(cr, uid, ids, context=context):
if line.product_id and line.product_id.type != 'service':
return True
return super(sale_order_line, self).need_procurement(cr, uid, ids, context=context)
def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
res = {}
@@ -396,6 +400,17 @@ class stock_location_route(osv.osv):
class stock_picking(osv.osv):
_inherit = "stock.picking"
def _get_partner_to_invoice(self, cr, uid, picking, context=None):
""" Inherit the original function of the 'stock' module
We select the partner of the sales order as the partner of the customer invoice
"""
saleorder_ids = self.pool['sale.order'].search(cr, uid, [('procurement_group_id' ,'=', picking.group_id.id)], context=context)
saleorders = self.pool['sale.order'].browse(cr, uid, saleorder_ids, context=context)
if saleorders and saleorders[0]:
saleorder = saleorders[0]
return saleorder.partner_invoice_id.id
return super(stock_picking, self)._get_partner_to_invoice(cr, uid, picking, context=context)
def _get_sale_id(self, cr, uid, ids, name, args, context=None):
sale_obj = self.pool.get("sale.order")
res = {}
+7 -2
View File
@@ -206,11 +206,13 @@ class procurement_order(osv.osv):
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
def run(self, cr, uid, ids, autocommit=False, context=None):
res = super(procurement_order, self).run(cr, uid, ids, autocommit=autocommit, context=context)
new_ids = [x.id for x in self.browse(cr, uid, ids, context=context) if x.state not in ('running', 'done', 'cancel')]
res = super(procurement_order, self).run(cr, uid, new_ids, autocommit=autocommit, context=context)
#after all the procurements are run, check if some created a draft stock move that needs to be confirmed
#(we do that in batch because it fasts the picking assignation and the picking state computation)
move_to_confirm_ids = []
for procurement in self.browse(cr, uid, ids, context=context):
for procurement in self.browse(cr, uid, new_ids, context=context):
if procurement.state == "running" and procurement.rule_id and procurement.rule_id.action == "move":
move_to_confirm_ids += [m.id for m in procurement.move_ids if m.state == 'draft']
if move_to_confirm_ids:
@@ -223,6 +225,9 @@ class procurement_order(osv.osv):
'''
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
if not procurement.move_ids:
return True
cancel_test_list = [x.state == 'cancel' for x in procurement.move_ids]
done_cancel_test_list = [x.state in ('done', 'cancel') for x in procurement.move_ids]
at_least_one_cancel = any(cancel_test_list)
+5 -1
View File
@@ -8,12 +8,16 @@
<record id="product.product_product_4" model="product.product">
<field name="type">product</field>
</record>
<record id="product.product_product_5" model="product.product">
<field name="type">product</field>
</record>
<record id="product.product_product_5b" model="product.product">
<field name="type">product</field>
</record>
<record id="product.product_product_6" model="product.product">
<field name="type">product</field>
</record>
+1 -1
View File
@@ -1269,6 +1269,7 @@ class stock_picking(osv.osv):
move_obj.action_confirm(cr, uid, moves, context=context)
return moves
def rereserve_quants(self, cr, uid, picking, move_ids=[], context=None):
""" Unreserve quants then try to reassign quants."""
stock_move_obj = self.pool.get('stock.move')
@@ -2395,7 +2396,6 @@ class stock_move(osv.osv):
defaults = {
'product_uom_qty': uom_qty,
'product_uos_qty': uos_qty,
'state': move.state,
'procure_method': 'make_to_stock',
'restrict_lot_id': restrict_lot_id,
'restrict_partner_id': restrict_partner_id,
+1 -1
View File
@@ -60,7 +60,7 @@
<field name="location_id" ref="stock_location_14"/>
</record>
<record id="stock_inventory_line_15" model="stock.inventory.line">
<field name="product_id" ref="product.product_product_5"/>
<field name="product_id" ref="product.product_product_5b"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="inventory_id" ref="stock_inventory_0"/>
<field name="product_qty">8.0</field>
+2 -2
View File
@@ -26,7 +26,7 @@
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<field name="standard_price" position="replace">
<field name="cost_method" groups="stock_account.group_inventory_valuation"/>
<field name="cost_method" groups="stock_account.group_inventory_valuation" attrs="{'invisible': [('type','=','service')]}"/>
<label string="Cost Price" for="standard_price" align="1.0" groups="base.group_user"/>
<div groups="base.group_user">
<field name="standard_price" attrs="{'readonly':['&amp;', ('valuation','=','real_time'), ('cost_method', 'in', ['standard', 'average'])]}" nolabel="1"/>
@@ -36,7 +36,7 @@
</div>
</field>
<xpath expr="//group[@name='properties']" position="before">
<group groups="stock_account.group_inventory_valuation">
<group groups="stock_account.group_inventory_valuation" attrs="{'invisible': [('type','=','service')]}">
<separator string="Inventory Valuation" colspan="4"/>
<group colspan="2" col="2">
<field name="valuation" attrs="{'readonly':[('type', '=', 'service')]}"/>
+6
View File
@@ -38,4 +38,10 @@ class stock_config_settings(osv.osv_memory):
help="""Install the module that allows to affect landed costs on pickings, and split them onto the different products."""),
}
def onchange_landed_costs(self, cr, uid, ids, module_landed_costs, context=None):
if module_landed_costs:
return {'value': {'group_stock_inventory_valuation': True}}
return {}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+1 -1
View File
@@ -19,7 +19,7 @@
<label for="module_stock_invoice_directly"/>
</div>
<div>
<field name="module_stock_landed_costs" class="oe_inline"/>
<field name="module_stock_landed_costs" on_change="onchange_landed_costs(module_stock_landed_costs)" class="oe_inline"/>
<label for="module_stock_landed_costs"/>
</div>
</div>
+15 -2
View File
@@ -190,6 +190,14 @@ class stock_picking(osv.osv):
invoice_obj = self.pool.get('account.invoice')
return invoice_obj.create(cr, uid, vals, context=context)
def _get_partner_to_invoice(self, cr, uid, picking, context=None):
""" Gets the partner that will be invoiced
Note that this function is inherited in the sale and purchase modules
@param picking: object of the picking for which we are selecting the partner to invoice
@return: object of the partner to invoice
"""
return picking.partner_id and picking.partner_id.id
def action_invoice_create(self, cr, uid, ids, journal_id, group=False, type='out_invoice', context=None):
""" Creates invoice based on the invoice state selected for picking.
@param journal_id: Id of journal
@@ -200,7 +208,12 @@ class stock_picking(osv.osv):
context = context or {}
todo = {}
for picking in self.browse(cr, uid, ids, context=context):
key = group and picking.id or True
partner = self._get_partner_to_invoice(cr, uid, picking, context)
#grouping is based on the invoiced partner
if group:
key = partner
else:
key = picking.id
for move in picking.move_lines:
if move.invoice_state == '2binvoiced':
if (move.state != 'cancel') and not move.scrapped:
@@ -208,7 +221,7 @@ class stock_picking(osv.osv):
todo[key].append(move)
invoices = []
for moves in todo.values():
invoices = self._invoice_create_line(cr, uid, moves, journal_id, type, context=context)
invoices += self._invoice_create_line(cr, uid, moves, journal_id, type, context=context)
return invoices
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, origin, context=None):
+2 -2
View File
@@ -18,6 +18,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import stock_invoice_onshipping
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import fields, osv
from openerp.tools.translate import _
class stock_invoice_onshipping(osv.osv_memory):
_inherit = "stock.invoice.onshipping"
def _get_journal_type(self, cr, uid, context=None):
if context is None:
context = {}
res_ids = context and context.get('active_ids', [])
pick_obj = self.pool.get('stock.picking')
pickings = pick_obj.browse(cr, uid, res_ids, context=context)
pick = pickings and pickings[0]
src_usage = pick.move_lines[0].location_id.usage
dest_usage = pick.move_lines[0].location_dest_id.usage
pick_purchase = pick.move_lines and pick.move_lines[0].purchase_line_id and pick.move_lines[0].purchase_line_id.order_id.invoice_method == 'picking'
if pick.picking_type_id.code == 'outgoing' and src_usage == 'supplier' and dest_usage == 'customer' and pick_purchase:
return 'purchase'
else:
return super(stock_invoice_onshipping, self)._get_journal_type(cr, uid, context=context)
_defaults = {
'journal_type': _get_journal_type,
}
+2 -2
View File
@@ -60,7 +60,7 @@
</field>
</record>
<record id="product.product_product_5" model="product.product">
<record id="product.product_product_5b" model="product.product">
<field name="website_published" eval="True"/>
<field name="website_size_x">2</field>
<field name="website_style_ids" eval="[(6,0,[ref('website_sale.image_promo')])]"/>
@@ -688,7 +688,7 @@ Weight: 1.1 ounces</field>
<record id="product.product_product_4_product_template" model="product.template">
<field name="public_categ_ids" eval="[(6,0,[ref('product.Computer_all_in_one')])]"/>
</record>
<record id="product.product_product_5_product_template" model="product.template">
<record id="product.product_product_5b_product_template" model="product.template">
<field name="public_categ_ids" eval="[(6,0,[ref('product.Speakers')])]"/>
</record>
<record id="product.product_product_6_product_template" model="product.template">