[MRG] merge with main branch

bzr revid: tpa@tinyerp.com-20130906061722-mgc4x1rbcpsknb0r
This commit is contained in:
Turkesh Patel (Open ERP) 2013-09-06 11:47:22 +05:30
commit e30ba1b116
11 changed files with 146 additions and 58 deletions

View File

@ -33,7 +33,7 @@ class stock_picking(osv.osv):
'''Return ids of created invoices for the pickings'''
res = super(stock_picking,self).action_invoice_create(cr, uid, ids, journal_id, group, type, context=context)
if type == 'in_refund':
for inv in self.pool.get('account.invoice').browse(cr, uid, res.values(), context=context):
for inv in self.pool.get('account.invoice').browse(cr, uid, res, context=context):
for ol in inv.invoice_line:
if ol.product_id:
oa = ol.product_id.property_stock_account_output and ol.product_id.property_stock_account_output.id
@ -45,7 +45,7 @@ class stock_picking(osv.osv):
self.pool.get('account.invoice.line').write(cr, uid, [ol.id], {'account_id': a})
elif type == 'in_invoice':
for inv in self.pool.get('account.invoice').browse(cr, uid, res.values(), context=context):
for inv in self.pool.get('account.invoice').browse(cr, uid, res, context=context):
for ol in inv.invoice_line:
if ol.product_id:
oa = ol.product_id.property_stock_account_input and ol.product_id.property_stock_account_input.id

View File

@ -32,7 +32,7 @@ You can define your own carrier and delivery grids for prices. When creating
invoices from picking, OpenERP is able to add and compute the shipping line.
""",
'author': 'OpenERP SA',
'depends': ['sale', 'purchase', 'stock'],
'depends': ['sale', 'purchase', 'stock_account'],
'data': [
'security/ir.model.access.csv',
'delivery_report.xml',

File diff suppressed because one or more lines are too long

View File

@ -127,8 +127,8 @@ class stock_picking(osv.osv):
result = super(stock_picking, self).action_invoice_create(cr, uid,
ids, journal_id=journal_id, group=group, type=type,
context=context)
for picking in picking_obj.browse(cr, uid, result.keys(), context=context):
invoice = invoice_obj.browse(cr, uid, result[picking.id], context=context)
for picking in picking_obj.browse(cr, uid, result, context=context):
invoice = invoice_obj.browse(cr, uid, picking.id, context=context)
invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context)
if invoice_line:
invoice_line_obj.create(cr, uid, invoice_line)

View File

@ -685,7 +685,11 @@ class purchase_order(osv.osv):
def _prepare_order_line_move(self, cr, uid, order, order_line, picking_id, context=None):
''' prepare the stock move data from the PO line '''
type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'picking_type_in')[1]
type = self.pool.get("stock.picking.type").browse(cr, uid, type_id, context=context)
price_unit = order_line.price_unit
if order_line.product_uom.id != order_line.product_id.uom_id.id:
price_unit *= order_line.product_uom.factor
if order.currency_id.id != order.company_id.currency_id.id:
price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, context=context)
return {
'name': order_line.name or '',
@ -704,7 +708,7 @@ class purchase_order(osv.osv):
'state': 'draft',
'purchase_line_id': order_line.id,
'company_id': order.company_id.id,
'price_unit': order_line.price_unit,
'price_unit': price_unit,
'picking_type_id': type_id,
}

View File

@ -26,28 +26,11 @@
product_uom: product.product_uom_categ_kgm
price_unit: 60.0
name: 'Average Ice Cream'
-
I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€
-
!record {model: purchase.order, id: purchase_order_average2}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
pricelist_id: 1
order_line:
- product_id: product_average_icecream
product_qty: 30.0
product_uom: product.product_uom_categ_kgm
price_unit: 80.0
name: 'Average Ice Cream'
-
I confirm the first purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average1}
-
I confirm the second purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average2}
-
I check the "Approved" status of purchase order 1
-
!assert {model: purchase.order, id: purchase_order_average1}:
@ -66,6 +49,23 @@
assert product.qty_available == 10.0, 'Wrong quantity in stock after first reception'
assert product.standard_price == 60.0, 'Standard price should be the price of the first reception!'
-
I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€
-
!record {model: purchase.order, id: purchase_order_average2}:
partner_id: base.res_partner_3
location_id: stock.stock_location_stock
pricelist_id: 1
order_line:
- product_id: product_average_icecream
product_qty: 30.0
product_uom: product.product_uom_categ_kgm
price_unit: 80.0
name: 'Average Ice Cream'
-
I confirm the second purchase order
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average2}
-
Process the reception of purchase order 2
-
!python {model: stock.picking}: |
@ -88,7 +88,9 @@
picking_id: outgoing_average_shipment
product_id: product_average_icecream
product_uom: product.product_uom_kgm
product_qty: 20.0
location_id: stock.stock_location_stock
location_dest_id: stock.stock_location_customers
product_uom_qty: 20.0
-
I assign this outgoing shipment and process the delivery
-
@ -102,7 +104,7 @@
assert self.browse(cr, uid, ref("product_average_icecream")).standard_price == 75.0, 'Standard price should not have changed with outgoing picking!'
assert self.browse(cr, uid, ref("product_average_icecream")).qty_available == 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong'
-
Make a new purchase order with 500 g Average Ice Cream at a price of 100 TODO the unit_price is 1 here
Make a new purchase order with 500 g Average Ice Cream at a price of 0.2€/g
-
!record {model: purchase.order, id: purchase_order_average3}:
partner_id: base.res_partner_3
@ -112,7 +114,7 @@
- product_id: product_average_icecream
product_qty: 500.0
product_uom: product.product_uom_gram
price_unit: 1.0
price_unit: 0.2
name: 'Average Ice Cream'
-
I confirm the first purchase order
@ -125,9 +127,9 @@
pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_average3")).picking_ids
self.do_partial(cr, uid, [pick_ids[0].id])
-
Check price is (75.0*20 + 500) / 20.5 = 97.56097561
Check price is (75.0*20 + 200*0.5) / 20.5 = 78.04878
-
!python {model: product.product}: |
product = self.browse(cr, uid, ref("product_average_icecream"))
assert product.qty_available == 20.5, 'Reception of purchase order in grams leads to wrong quantity in stock'
assert round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2) == 97.56, 'Standard price as average price of third reception with other UoM incorrect!'
assert round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2) == 78.05, 'Standard price as average price of third reception with other UoM incorrect! Got %s instead of 78.05' % (round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2),)

View File

@ -23,6 +23,7 @@ from datetime import datetime, timedelta
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, DATETIME_FORMATS_MAP, float_compare
from dateutil.relativedelta import relativedelta
from openerp.osv import fields, osv
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
import pytz
from openerp import SUPERUSER_ID
@ -152,9 +153,12 @@ class sale_order(osv.osv):
#compute the number of delivery orders to display
pick_ids = []
ctx = {}
for so in self.browse(cr, uid, ids, context=context):
pick_ids += [picking.id for picking in so.picking_ids]
if len(pick_ids)>0:
pick_type = self.pool.get('stock.picking').browse(cr, uid, pick_ids[0], context=context)['picking_type_id'].id
ctx = eval(result['context'],{'active_id': pick_type}, nocopy=True)
#choose the view_mode accordingly
if len(pick_ids) > 1:
result['domain'] = "[('id','in',["+','.join(map(str, pick_ids))+"])]"
@ -162,6 +166,9 @@ class sale_order(osv.osv):
res = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_form')
result['views'] = [(res and res[1] or False, 'form')]
result['res_id'] = pick_ids and pick_ids[0] or False
result.update({
'context': ctx,
})
return result
# TODO: FP Note: I guess it's better to do:

View File

@ -980,13 +980,13 @@ class stock_move(osv.osv):
_log_create = False
def get_price_unit(self, cr, uid, move, context=None):
""" Returns the unit price to store on the move """
""" Returns the unit price to store on the quant """
return move.price_unit or move.product_id.standard_price
def name_get(self, cr, uid, ids, context=None):
res = []
for line in self.browse(cr, uid, ids, context=context):
name = line.location_id.name+' > '+line.location_dest_id.name
name = line.location_id.name + ' > ' + line.location_dest_id.name
if line.product_id.code:
name = line.product_id.code + ': ' + name
if line.picking_id.origin:
@ -1126,8 +1126,7 @@ class stock_move(osv.osv):
"* Available: When products are reserved, it is set to \'Available\'.\n"\
"* Done: When the shipment is processed, the state is \'Done\'."),
'price_unit': fields.float('Unit Price', help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"), # as it's a technical field, we intentionally don't provide the digits attribute
'price_currency_id': fields.many2one('res.currency', 'Currency for average price', help="Technical field used to record the currency chosen by the user during a picking confirmation (when average price costing method is used)"),
'price_unit': fields.float('Unit Price', help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used). Value given in company currency and in product uom."), # as it's a technical field, we intentionally don't provide the digits attribute
'company_id': fields.many2one('res.company', 'Company', required=True, select=True),
'backorder_id': fields.related('picking_id','backorder_id',type='many2one', relation="stock.picking", string="Back Order of", select=True),
@ -1875,20 +1874,19 @@ class stock_inventory_line(osv.osv):
'prod_lot_id': fields.many2one('stock.production.lot', 'Serial Number', domain="[('product_id','=',product_id)]"),
'state': fields.related('inventory_id', 'state', type='char', string='Status', readonly=True),
'real_qty':fields.related('product_id','qty_available', type='float', string='Real Quantity'),
'partner_id': fields.many2one('res.partner', 'Owner'),
}
def _resolve_inventory_line(self, cr, uid, inventory_line, theorical_lines, context=None):
found = False
#first try to match the inventory line with a theorical line with same product, lot and location
for th_line in theorical_lines:
if th_line['location_id'] == inventory_line.location_id.id and th_line['product_id'] == inventory_line.product_id.id and th_line['prod_lot_id'] == inventory_line.prod_lot_id.id:
th_line['product_qty'] -= inventory_line.product_qty
found = True
break
#then if the line was not found, try to match the inventory line with a theorical line with same product and location (only if it has no lot information given)
if not found:
for th_line in theorical_lines:
if th_line['location_id'] == inventory_line.location_id.id and th_line['product_id'] == inventory_line.product_id.id and not inventory_line.prod_lot_id.id:
#We try to match the inventory line with a theorical line with same product, lot and location and owner
#or match with same product and lot (only if owner is missing)
#or match with same product and owner (only if lot is missing)
#or match with same product (only if owner and lot are missing)
if th_line['location_id'] == inventory_line.location_id.id and th_line['product_id'] == inventory_line.product_id.id:
if (not inventory_line.prod_lot_id.id or th_line['prod_lot_id'] == inventory_line.prod_lot_id.id) and (not inventory_line.partner_id.id or th_line['partner_id'] == inventory_line.partner_id.id):
th_line['product_qty'] -= inventory_line.product_qty
found = True
break
@ -2399,6 +2397,9 @@ class stock_picking_type(osv.osv):
else:
return {'value': result}
def _get_name(self, cr, uid, ids, field_names, arg, context=None):
return dict(self.name_get(cr, uid, ids, context=context))
def name_get(self, cr, uid, ids, context=None):
"""Overides orm name_get method to display 'Warehouse_name: PickingType_name' """
if not isinstance(ids, list):
@ -2420,6 +2421,7 @@ class stock_picking_type(osv.osv):
_columns = {
'name': fields.char('name', translate=True, required=True),
'complete_name': fields.function(_get_name, type='char', string='Name'),
'pack': fields.boolean('Prefill Pack Operations', help='This picking type needs packing interface'),
'auto_force_assign': fields.boolean('Automatic Availability', help='This picking type does\'t need to check for the availability in source location.'),
'color': fields.integer('Color Index'),
@ -2427,6 +2429,7 @@ class stock_picking_type(osv.osv):
'sequence_id': fields.many2one('ir.sequence', 'Sequence', required=True),
'default_location_src_id': fields.many2one('stock.location', 'Default Source Location'),
'default_location_dest_id': fields.many2one('stock.location', 'Default Destination Location'),
#TODO: change field name to "code" as it's not a many2one anymore
'code_id': fields.selection([('incoming', 'Suppliers'), ('outgoing', 'Customers'), ('internal', 'Internal')], 'Picking type code', required=True),
'return_picking_type_id': fields.many2one('stock.picking.type', 'Picking Type for Returns'),
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'),

View File

@ -132,7 +132,7 @@
<notebook attrs="{'invisible':[('state','=','draft')]}">
<page string="Inventory Details" >
<button name="set_checked_qty" states="confirm" string="⇒ Set Checked Quantity to 0" type="object" class="oe_link oe_right" groups="stock.group_stock_user"/>
<field name="line_ids" string="Inventory Details" context="{'default_location_id': location_id, 'default_product_id': product_id, 'default_prod_lot_id': lot_id, 'default_package_id': package_id}">
<field name="line_ids" string="Inventory Details" context="{'default_location_id': location_id, 'default_product_id': product_id, 'default_prod_lot_id': lot_id, 'default_package_id': package_id, 'default_partner_id': partner_id}">
<tree string="Inventory Details" editable="bottom" colors="blue: product_qty != real_qty">
<field context="{'location':location_id, 'uom':product_uom_id, 'to_date':parent.date}" name="product_id" on_change="on_change_product_id(location_id,product_id,product_uom_id,parent.date)" domain="[('type','=','product')]"/>
<field name="real_qty" readonly="1"/>
@ -140,6 +140,7 @@
<field name="product_uom_id" groups="product.group_uom"/>
<field name="prod_lot_id"/>
<field name="package_id"/>
<field name="partner_id"/>
<field domain="[('usage','=','internal')]" name="location_id" groups="stock.group_locations"/>
<field name="state" invisible="True"/>
</tree>
@ -1180,7 +1181,7 @@
<field name="model">stock.picking.type</field>
<field name="arch" type="xml">
<tree string="Picking Types">
<field name="name"/>
<field name="complete_name"/>
<field name="sequence_id"/>
<field name="pack"/>
</tree>
@ -1222,7 +1223,7 @@
<field name="model">stock.picking.type</field>
<field name="arch" type="xml">
<kanban version="7.0" class="oe_background_grey">
<field name="name"/>
<field name="complete_name"/>
<field name="color"/>
<field name="count_picking"/>
<field name="count_picking_waiting"/>
@ -1243,7 +1244,7 @@
</ul>
</div>
<div class="oe_kanban_content">
<h4 class="oe_center"><field name="name"/></h4>
<h4 class="oe_center"><field name="complete_name"/></h4>
<div class="oe_right">
<a name="%(action_stock_stock_ui)d" type="action">
<img src="/stock/static/src/img/scan.png"

View File

@ -206,10 +206,27 @@ class stock_move(osv.osv):
def product_price_update(self, cr, uid, ids, context=None):
'''
This method adapts the price on the product when necessary (if the cost_method is 'real'), so that a return or an inventory loss is made using the last value used for an outgoing valuation.
This method adapts the price on the product when necessary
'''
product_obj = self.pool.get('product.product')
for move in self.browse(cr, uid, ids, context=context):
#adapt standard price on incomming moves if the product cost_method is 'average'
if (move.location_id.usage == 'supplier') and (move.product_id.cost_method == 'average'):
product = move.product_id
company_currency_id = move.company_id.currency_id.id
ctx = {'currency_id': company_currency_id}
product_avail = product.qty_available
if product.qty_available <= 0:
new_std_price = move.price_unit
else:
# Get the standard price
amount_unit = product.price_get('standard_price', context=ctx)[product.id]
new_std_price = (amount_unit * (product_avail - move.product_qty) + (move.price_unit * move.product_qty)) / product_avail
# Write the field according to price type field
product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=context)
#adapt standard price on outgoing moves if the product cost_method is 'real', so that a return
#or an inventory loss is made using the last value used for an outgoing valuation.
if move.product_id.cost_method == 'real' and move.location_dest_id.usage != 'internal':
if any([q.qty <= 0 for q in move.quant_ids]):
#if there is a negative quant, the standard price shouldn't be updated

View File

@ -1,3 +1,12 @@
-
Create Two Customers
-
!record {model: res.partner, id: customer_1}:
name: Customer 1
-
!record {model: res.partner, id: customer_2}:
name: Customer 2
-
Create Panama in Location structure
-
@ -66,7 +75,7 @@
Create picking type internal for this warehouse
-
!record {model: stock.picking.type, id: picking_type_santiago_internal}:
name: Deliveries
name: Internal
code_id: internal
sequence_id: stock.seq_picking_type_internal
warehouse_id: wh_panama_santiago
@ -129,7 +138,7 @@
Create picking type internal for warehouse panama main
-
!record {model: stock.picking.type, id: picking_type_main_internal}:
name: Deliveries
name: Internal
code_id: internal
sequence_id: stock.seq_picking_type_internal
warehouse_id: wh_panama_main
@ -169,7 +178,7 @@
-
Create Ship Route for main panama warehouse
-
!record {model: stock.location.route, id: route_wh_panama_main_push}:
!record {model: stock.location.route, id: route_wh_panama_main_ship}:
name: Ship main panama
pull_ids:
- invoice_state: none
@ -189,7 +198,7 @@
-
Create Ship Route for panama santiago warehouse
-
!record {model: stock.location.route, id: route_wh_panama_santiago_push}:
!record {model: stock.location.route, id: route_wh_panama_santiago_ship}:
name: Ship panama santiago
pull_ids:
- invoice_state: none
@ -206,12 +215,17 @@
picking_type_id: picking_type_santiago_out
procure_method: make_to_order
action: move
-
!python {model: stock.warehouse}: |
self.write(cr, uid, [ref('wh_panama_main')], {'route_id': ref('route_wh_panama_main_ship')}, context=context)
self.write(cr, uid, [ref('wh_panama_santiago')], {'route_id': ref('route_wh_panama_santiago_ship')}, context=context)
-
Create Products
-
!record {model: product.product, id: product_A}:
name: Product A
type: consu
type: product
categ_id: product.product_category_1
list_price: 100.0
standard_price: 70.0
@ -221,7 +235,7 @@
-
!record {model: product.product, id: product_B}:
name: Product B
type: consu
type: product
categ_id: product.product_category_1
list_price: 150.0
standard_price: 150.0
@ -231,7 +245,7 @@
-
!record {model: product.product, id: product_C}:
name: Product C
type: consu
type: product
categ_id: product.product_category_1
list_price: 200.0
standard_price: 150.0
@ -241,7 +255,7 @@
-
!record {model: product.product, id: product_D}:
name: Product D
type: consu
type: product
categ_id: product.product_category_1
list_price: 300.0
standard_price: 280.0
@ -495,4 +509,45 @@
I confirm Bin1 inventory
-
!python {model: stock.inventory}: |
self.action_done(cr, uid, [ref('inventory_stock1_area1_bin1')], context=context)
self.action_done(cr, uid, [ref('inventory_stock1_area1_bin1')], context=context)
-
I create some sale order in draft
-
!record {model: sale.order, id: so1}:
partner_id: customer_1
warehouse_id: wh_panama_main
order_line:
- product_id: product_A
product_uom_qty: 7
- product_id: product_B
product_uom_qty: 10
- product_id: product_C
product_uom_qty: 6
- product_id: product_D
product_uom_qty: 2
-
!record {model: sale.order, id: so2}:
partner_id: customer_1
warehouse_id: wh_panama_main
order_line:
- product_id: product_E
product_uom_qty: 5
- product_id: product_F
product_uom_qty: 20
- product_id: product_G
product_uom_qty: 12
- product_id: product_H
product_uom_qty: 8
-
!record {model: sale.order, id: so3}:
partner_id: customer_2
warehouse_id: wh_panama_santiago
order_line:
- product_id: product_A
product_uom_qty: 5
- product_id: product_D
product_uom_qty: 3
- product_id: product_G
product_uom_qty: 12