From 064b1a3a404eef5c5140c33d405c9ac1ea0066b0 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 1 Sep 2014 15:39:32 +0200 Subject: [PATCH 01/12] [IMP] Old hack where uom_id had to be empty in on_change [IMP] Add purchase order origin on picking [WIP] Picking type on move for location on routing [IMP] Provide extra function for custom buttons on picking [IMP] Action assign optim [IMP] Push apply should take invoice_state into account. Propagation of cancel of stock moves should depend on procurement rule --- addons/mrp/mrp.py | 7 +++++++ addons/purchase/purchase.py | 4 +++- addons/sale_stock/sale_stock.py | 2 +- addons/stock/stock.py | 30 ++++++++++++++++++------------ addons/stock_account/stock.py | 5 +++++ 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 9e6afe3cc2c..2c484808064 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -1059,19 +1059,25 @@ class mrp_production(osv.osv): return "make_to_order" return "make_to_stock" + + def _create_previous_move(self, cr, uid, move_id, product, source_location_id, dest_location_id, context=None): ''' 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) ''' + stock_move = self.pool.get('stock.move') + type_obj = self.pool.get('stock.picking.type') + types = type_obj.search(cr, uid, [('code','=','outgoing')], 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 +1115,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): diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index fb2a40d2741..2cd492e1b9f 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -741,6 +741,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 +822,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) diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py index 4371a40a100..7fef11b7472 100644 --- a/addons/sale_stock/sale_stock.py +++ b/addons/sale_stock/sale_stock.py @@ -289,7 +289,7 @@ class sale_order_line(osv.osv): product_obj = self.pool.get('product.product') warning = {} 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: diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 47bf0ad29bd..acbc9b672c3 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3503,6 +3503,22 @@ 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 +3535,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, }) diff --git a/addons/stock_account/stock.py b/addons/stock_account/stock.py index 644128f2b5f..7a0d5ccca3b 100644 --- a/addons/stock_account/stock.py +++ b/addons/stock_account/stock.py @@ -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 #---------------------------------------------------------- From 8b204e675197861e4f226d69fe18e5ea14698820 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Wed, 3 Sep 2014 15:24:49 +0200 Subject: [PATCH 02/12] [IMP] Make sure property_ids on sale order line are visible and able to work --- addons/sale_mrp/sale_mrp.py | 10 ++++++++++ addons/sale_mrp/sale_mrp_view.xml | 13 +++++++++++++ addons/sale_stock/sale_stock_view.xml | 4 ---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/addons/sale_mrp/sale_mrp.py b/addons/sale_mrp/sale_mrp.py index 52f9f018841..082323ad580 100644 --- a/addons/sale_mrp/sale_mrp.py +++ b/addons/sale_mrp/sale_mrp.py @@ -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 diff --git a/addons/sale_mrp/sale_mrp_view.xml b/addons/sale_mrp/sale_mrp_view.xml index 3c2771f55a5..71e0aada1ea 100644 --- a/addons/sale_mrp/sale_mrp_view.xml +++ b/addons/sale_mrp/sale_mrp_view.xml @@ -16,5 +16,18 @@ + + sale.order.form.sale.stock.mrp + sale.order + + + + + + + + + diff --git a/addons/sale_stock/sale_stock_view.xml b/addons/sale_stock/sale_stock_view.xml index 48e41f9f28c..f3db20171b4 100644 --- a/addons/sale_stock/sale_stock_view.xml +++ b/addons/sale_stock/sale_stock_view.xml @@ -62,10 +62,6 @@ days - From a0d855ffad5851ba8f2873a74f82509946e67423 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Wed, 3 Sep 2014 19:15:10 +0200 Subject: [PATCH 03/12] [IMP] Inter-company pricing: put price on move when only partner and not connected to sale or purchase + invoice_state inverse function --- addons/purchase/purchase.py | 2 +- addons/purchase/stock.py | 3 +-- addons/stock/stock.py | 27 ++++++++++++++++++----- addons/stock_account/stock.py | 41 ++++++++++++++++++++++++++++++----- 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 2cd492e1b9f..02296ce4650 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -727,7 +727,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 diff --git a/addons/purchase/stock.py b/addons/purchase/stock.py index 508b9a0babf..75fabe42f5c 100644 --- a/addons/purchase/stock.py +++ b/addons/purchase/stock.py @@ -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,7 +68,7 @@ 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 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): diff --git a/addons/stock/stock.py b/addons/stock/stock.py index acbc9b672c3..531b2fa6257 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1525,12 +1525,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 +2014,26 @@ 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 multi-company + """ + if move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal' and not move.price_unit: + partner = move.partner_id or (move.picking_id and move.picking_id.partner_id) + 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 not price: + 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 +2047,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: diff --git a/addons/stock_account/stock.py b/addons/stock_account/stock.py index 7a0d5ccca3b..e4d58e39bda 100644 --- a/addons/stock_account/stock.py +++ b/addons/stock_account/stock.py @@ -96,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 + if move.partner_id: + if move.partner_id.property_product_pricelist_purchase and move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal': + currency = move.partner_id.property_product_pricelist_purchase.currency_id.id + elif move.partner_id.property_product_pricelist and move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal': + currency = move.partner_id.property_product_pricelist.currency_id.id + return move.picking_id.partner_id, 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) @@ -110,10 +116,26 @@ 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 + if move_line.partner_id: + return move_line.price_unit + else: + # Take the user company and pricetype + # TODO: This intercompany still needed? + 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 + 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], + product, 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): @@ -172,13 +194,20 @@ 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), From 246c425226908ebb43d126da9c1632e8b3c9f1bd Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Thu, 4 Sep 2014 14:54:39 +0200 Subject: [PATCH 04/12] [WIP] Pricelist of purchase is not in stock only and remove product_manufacturer module in view + manufacturer --- addons/mrp/report/bom_structure.py | 4 ++-- addons/mrp/res_config.py | 1 + addons/mrp/res_config_view.xml | 4 ---- addons/product/product.py | 1 + addons/purchase/stock.py | 31 ++++++++++++++++++++++++++++++ addons/stock/stock.py | 19 +++--------------- addons/stock_account/stock.py | 11 +++++------ 7 files changed, 43 insertions(+), 28 deletions(-) diff --git a/addons/mrp/report/bom_structure.py b/addons/mrp/report/bom_structure.py index 1b286feac46..c8a3132a679 100644 --- a/addons/mrp/report/bom_structure.py +++ b/addons/mrp/report/bom_structure.py @@ -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: diff --git a/addons/mrp/res_config.py b/addons/mrp/res_config.py index 71635cc9e6e..5edebfa0772 100644 --- a/addons/mrp/res_config.py +++ b/addons/mrp/res_config.py @@ -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' diff --git a/addons/mrp/res_config_view.xml b/addons/mrp/res_config_view.xml index d9af7a688bc..7dfba32450c 100644 --- a/addons/mrp/res_config_view.xml +++ b/addons/mrp/res_config_view.xml @@ -54,10 +54,6 @@