diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 4c96986c635..0618a998f03 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -1279,6 +1279,21 @@ class stock_picking(osv.osv):
stock_move_obj.do_unreserve(cr, uid, move_ids, context=context)
stock_move_obj.action_assign(cr, uid, move_ids, context=context)
+ @api.cr_uid_ids_context
+ def do_enter_transfer_details(self, cr, uid, picking, context=None):
+ if not context:
+ context = {}
+
+ context.update({
+ 'active_model': self._name,
+ 'active_ids': picking,
+ 'active_id': len(picking) and picking[0] or False
+ })
+
+ created_id = self.pool['stock.transfer_details'].create(cr, uid, {'picking_id': len(picking) and picking[0] or False}, context)
+ return self.pool['stock.transfer_details'].wizard_view(cr, uid, created_id, context)
+
+
@api.cr_uid_ids_context
def do_transfer(self, cr, uid, picking_ids, context=None):
"""
@@ -1298,10 +1313,10 @@ class stock_picking(osv.osv):
todo_move_ids = []
if not all_op_processed:
todo_move_ids += self._create_extra_moves(cr, uid, picking, context=context)
-
+
picking.refresh()
#split move lines eventually
-
+
toassign_move_ids = []
for move in picking.move_lines:
remaining_qty = move.remaining_qty
@@ -3749,9 +3764,9 @@ class stock_pack_operation(osv.osv):
'product_uom_id': fields.many2one('product.uom', 'Product Unit of Measure'),
'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
'qty_done': fields.float('Quantity Processed', digits_compute=dp.get_precision('Product Unit of Measure')),
- 'package_id': fields.many2one('stock.quant.package', 'Package'), # 2
+ 'package_id': fields.many2one('stock.quant.package', 'Source Package'), # 2
'lot_id': fields.many2one('stock.production.lot', 'Lot/Serial Number'),
- 'result_package_id': fields.many2one('stock.quant.package', 'Container Package', help="If set, the operations are packed into this package", required=False, ondelete='cascade'),
+ 'result_package_id': fields.many2one('stock.quant.package', 'Destination Package', help="If set, the operations are packed into this package", required=False, ondelete='cascade'),
'date': fields.datetime('Date', required=True),
'owner_id': fields.many2one('res.partner', 'Owner', help="Owner of the quants"),
#'update_cost': fields.boolean('Need cost update'),
@@ -3759,8 +3774,8 @@ class stock_pack_operation(osv.osv):
'currency': fields.many2one('res.currency', string="Currency", help="Currency in which Unit cost is expressed", ondelete='CASCADE'),
'linked_move_operation_ids': fields.one2many('stock.move.operation.link', 'operation_id', string='Linked Moves', readonly=True, help='Moves impacted by this operation for the computation of the remaining quantities'),
'remaining_qty': fields.function(_get_remaining_qty, type='float', string='Remaining Qty'),
- 'location_id': fields.many2one('stock.location', 'Location From', required=True),
- 'location_dest_id': fields.many2one('stock.location', 'Location To', required=True),
+ 'location_id': fields.many2one('stock.location', 'Source Location', required=True),
+ 'location_dest_id': fields.many2one('stock.location', 'Destination Location', required=True),
'processed': fields.selection([('true','Yes'), ('false','No')],'Has been processed?', required=True),
}
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index 3cc31f3ec36..8d63e194dcd 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -634,9 +634,7 @@
-
-
-
+
@@ -645,6 +643,8 @@
+
+
@@ -673,20 +673,24 @@
-
+
-
-
+
+
-
+
+
+
+ If there is no product but a source package, this means the source package was moved entirely. If there is a product and a source package, the product was taken from the source package.
+
@@ -1338,7 +1342,7 @@
-
@@ -1911,7 +1915,7 @@
-
+
diff --git a/addons/stock/wizard/__init__.py b/addons/stock/wizard/__init__.py
index e6422a579f2..3ad8e0201b4 100644
--- a/addons/stock/wizard/__init__.py
+++ b/addons/stock/wizard/__init__.py
@@ -24,4 +24,4 @@ import stock_return_picking
import stock_change_product_qty
import make_procurement_product
import orderpoint_procurement
-
+import stock_transfer_details
diff --git a/addons/stock/wizard/stock_transfer_details.py b/addons/stock/wizard/stock_transfer_details.py
new file mode 100644
index 00000000000..831f225ca13
--- /dev/null
+++ b/addons/stock/wizard/stock_transfer_details.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-TODAY OpenERP S.A.
+#
+# 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 .
+#
+##############################################################################
+
+from openerp import models, fields, api
+from openerp.tools.translate import _
+import openerp.addons.decimal_precision as dp
+from datetime import datetime
+
+class stock_transfer_details(models.TransientModel):
+ _name = 'stock.transfer_details'
+ _description = 'Picking wizard'
+
+ picking_id = fields.Many2one('stock.picking', 'Picking')
+ item_ids = fields.One2many('stock.transfer_details_items', 'transfer_id', 'Items', domain=[('product_id', '!=', False)])
+ packop_ids = fields.One2many('stock.transfer_details_items', 'transfer_id', 'Packs', domain=[('product_id', '=', False)])
+ picking_source_location_id = fields.Many2one('stock.location', string="Head source location", related='picking_id.location_id', store=False, readonly=True)
+ picking_destination_location_id = fields.Many2one('stock.location', string="Head destination location", related='picking_id.location_dest_id', store=False, readonly=True)
+
+ def default_get(self, cr, uid, fields, context=None):
+ if context is None: context = {}
+ res = super(stock_transfer_details, self).default_get(cr, uid, fields, context=context)
+ picking_ids = context.get('active_ids', [])
+ active_model = context.get('active_model')
+
+ if not picking_ids or len(picking_ids) != 1:
+ # Partial Picking Processing may only be done for one picking at a time
+ return res
+ assert active_model in ('stock.picking'), 'Bad context propagation'
+ picking_id, = picking_ids
+ picking = self.pool.get('stock.picking').browse(cr, uid, picking_id, context=context)
+ items = []
+ packs = []
+ if not picking.pack_operation_ids:
+ picking.do_prepare_partial()
+ for op in picking.pack_operation_ids:
+ item = {
+ 'packop_id': op.id,
+ 'product_id': op.product_id.id,
+ 'product_uom_id': op.product_uom_id.id,
+ 'quantity': op.product_qty,
+ 'package_id': op.package_id.id,
+ 'lot_id': op.lot_id.id,
+ 'sourceloc_id': op.location_id.id,
+ 'destinationloc_id': op.location_dest_id.id,
+ 'result_package_id': op.result_package_id.id,
+ 'date': op.date,
+ 'owner_id': op.owner_id.id,
+ }
+ if op.product_id:
+ items.append(item)
+ elif op.package_id:
+ packs.append(item)
+ res.update(item_ids=items)
+ res.update(packop_ids=packs)
+ return res
+
+ @api.one
+ def do_detailed_transfer(self):
+ processed_ids = []
+ # Create new and update existing pack operations
+ for lstits in [self.item_ids, self.packop_ids]:
+ for prod in lstits:
+ pack_datas = {
+ 'product_id': prod.product_id.id,
+ 'product_uom_id': prod.product_uom_id.id,
+ 'product_qty': prod.quantity,
+ 'package_id': prod.package_id.id,
+ 'lot_id': prod.lot_id.id,
+ 'location_id': prod.sourceloc_id.id,
+ 'location_dest_id': prod.destinationloc_id.id,
+ 'result_package_id': prod.result_package_id.id,
+ 'date': prod.date if prod.date else datetime.now(),
+ 'owner_id': prod.owner_id.id,
+ }
+ if prod.packop_id:
+ prod.packop_id.write(pack_datas)
+ processed_ids.append(prod.packop_id.id)
+ else:
+ pack_datas['picking_id'] = self.picking_id.id
+ packop_id = self.env['stock.pack.operation'].create(pack_datas)
+ processed_ids.append(packop_id.id)
+ # Delete the others
+ packops = self.env['stock.pack.operation'].search(['&', ('picking_id', '=', self.picking_id.id), '!', ('id', 'in', processed_ids)])
+ for packop in packops:
+ packop.unlink()
+
+ # Execute the transfer of the picking
+ self.picking_id.do_transfer()
+
+ return True
+
+ @api.multi
+ def wizard_view(self):
+ view = self.env.ref('stock.view_stock_enter_transfer_details')
+
+ return {
+ 'name': _('Enter transfer details'),
+ 'type': 'ir.actions.act_window',
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'stock.transfer_details',
+ 'views': [(view.id, 'form')],
+ 'view_id': view.id,
+ 'target': 'new',
+ 'res_id': self.ids[0],
+ 'context': self.env.context,
+ }
+
+
+class stock_transfer_details_items(models.TransientModel):
+ _name = 'stock.transfer_details_items'
+ _description = 'Picking wizard items'
+
+ transfer_id = fields.Many2one('stock.transfer_details', 'Transfer')
+ packop_id = fields.Many2one('stock.pack.operation', 'Operation')
+ product_id = fields.Many2one('product.product', 'Product')
+ product_uom_id = fields.Many2one('product.uom', 'Product Unit of Measure')
+ quantity = fields.Float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), default = 1.0)
+ package_id = fields.Many2one('stock.quant.package', 'Source package', domain="['|', ('location_id', 'child_of', sourceloc_id), ('location_id','=',False)]")
+ lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number')
+ sourceloc_id = fields.Many2one('stock.location', 'Source Location', required=True)
+ destinationloc_id = fields.Many2one('stock.location', 'Destination Location', required=True)
+ result_package_id = fields.Many2one('stock.quant.package', 'Destination package', domain="['|', ('location_id', 'child_of', destinationloc_id), ('location_id','=',False)]")
+ date = fields.Datetime('Date')
+ owner_id = fields.Many2one('res.partner', 'Owner', help="Owner of the quants")
+
+
+
+ @api.multi
+ def split_quantities(self):
+ for det in self:
+ if det.quantity>1:
+ det.quantity = (det.quantity-1)
+ new_id = det.copy(context=self.env.context)
+ new_id.quantity = 1
+ new_id.packop_id = False
+ if self and self[0]:
+ return self[0].transfer_id.wizard_view()
+
+ @api.multi
+ def put_in_pack(self):
+ newpack = None
+ for packop in self:
+ if not packop.result_package_id:
+ if not newpack:
+ newpack = self.pool['stock.quant.package'].create(self._cr, self._uid, {'location_id': packop.destinationloc_id.id if packop.destinationloc_id else False}, self._context)
+ packop.result_package_id = newpack
+ if self and self[0]:
+ return self[0].transfer_id.wizard_view()
+
+ @api.multi
+ def product_id_change(self, product, uom=False):
+ result = {}
+ if product:
+ prod = self.env['product.product'].browse(product)
+ result['product_uom_id'] = prod.uom_id and prod.uom_id.id
+ return {'value': result, 'domain': {}, 'warning':{} }
+
+ @api.multi
+ def source_package_change(self, sourcepackage):
+ result = {}
+ if sourcepackage:
+ pack = self.env['stock.quant.package'].browse(sourcepackage)
+ result['sourceloc_id'] = pack.location_id and pack.location_id.id
+ return {'value': result, 'domain': {}, 'warning':{} }
diff --git a/addons/stock/wizard/stock_transfer_details.xml b/addons/stock/wizard/stock_transfer_details.xml
new file mode 100644
index 00000000000..c4528a0439f
--- /dev/null
+++ b/addons/stock/wizard/stock_transfer_details.xml
@@ -0,0 +1,63 @@
+
+
+
+
+ Enter transfer details
+ stock.transfer_details
+
+
+
+
+
+
+
diff --git a/addons/stock_account/stock_account_view.xml b/addons/stock_account/stock_account_view.xml
index 4f8c2122e55..a35a75144bc 100644
--- a/addons/stock_account/stock_account_view.xml
+++ b/addons/stock_account/stock_account_view.xml
@@ -31,7 +31,7 @@
stock.picking
-
+