diff --git a/addons/account_anglo_saxon/stock.py b/addons/account_anglo_saxon/stock.py index 1cf3ecf21ef..79aa54ed508 100644 --- a/addons/account_anglo_saxon/stock.py +++ b/addons/account_anglo_saxon/stock.py @@ -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 diff --git a/addons/delivery/__openerp__.py b/addons/delivery/__openerp__.py index 0ea891bb6ae..089dc3e14d7 100644 --- a/addons/delivery/__openerp__.py +++ b/addons/delivery/__openerp__.py @@ -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', diff --git a/addons/delivery/delivery_demo.xml b/addons/delivery/delivery_demo.xml index a05d16110d3..d085017c31d 100644 --- a/addons/delivery/delivery_demo.xml +++ b/addons/delivery/delivery_demo.xml @@ -22,7 +22,6 @@ Delivery service - make_to_order 10.0 10.0 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 diff --git a/addons/delivery/stock.py b/addons/delivery/stock.py index f0287c54913..3c1440cf951 100644 --- a/addons/delivery/stock.py +++ b/addons/delivery/stock.py @@ -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) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 4d42b22c65b..3b0f638263d 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -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, } diff --git a/addons/purchase/test/average_price.yml b/addons/purchase/test/average_price.yml index 79bae838f7e..f39a23076f0 100644 --- a/addons/purchase/test/average_price.yml +++ b/addons/purchase/test/average_price.yml @@ -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!' \ No newline at end of file + 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),) diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py index 055b4309d6d..97cc5056c51 100644 --- a/addons/sale_stock/sale_stock.py +++ b/addons/sale_stock/sale_stock.py @@ -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: diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 4a1f0a122d6..4654e1c0073 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -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'), diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 62dddfcf5fe..4af592e7baf 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -132,7 +132,7 @@