Merge from nse back-end partial picking wizard
This commit is contained in:
parent
b8b947ffa4
commit
3891892d9f
|
@ -75,6 +75,7 @@ Dashboard / Reports for Warehouse Management will include:
|
|||
'wizard/stock_return_picking_view.xml',
|
||||
'wizard/make_procurement_view.xml',
|
||||
'wizard/orderpoint_procurement_view.xml',
|
||||
'wizard/stock_transfer_details.xml',
|
||||
'stock_incoterms.xml',
|
||||
'stock_report.xml',
|
||||
'stock_view.xml',
|
||||
|
|
|
@ -120,3 +120,12 @@
|
|||
display: inline-block;
|
||||
margin: -7px;
|
||||
}
|
||||
|
||||
.oe_stock_scan_image_btn {
|
||||
/*height : 42px;*/
|
||||
}
|
||||
.oe_stock_scan_button {
|
||||
border: none !important;
|
||||
background: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
<div class="col-md-6 col-sm-4 col-xs-12 text-right">
|
||||
<h3>
|
||||
<button type="button" class='btn btn-default js_pick_pack js_putinpack'> Put in Pack </button>
|
||||
<button type="button" class='btn btn-danger js_drop_down'> Process </button>
|
||||
<button type="button" class='btn btn-danger js_drop_down fa fa-download'> Put in Cart </button>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
@ -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),
|
||||
}
|
||||
|
||||
|
|
|
@ -634,9 +634,7 @@
|
|||
<button name="action_confirm" states="draft" string="Mark as Todo" type="object" class="oe_highlight" groups="base.group_user"/>
|
||||
<button name="action_assign" states="confirmed,partially_available" string="Check Availability" type="object" class="oe_highlight" groups="base.group_user"/>
|
||||
<button name="force_assign" states="confirmed,waiting,partially_available" string="Force Availability" type="object" groups="base.group_user"/>
|
||||
<button name="do_transfer" states="assigned" string="Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('pack_operation_exist', '=', True)]}"/>
|
||||
<button name="do_partial_open_barcode" string="Enter Transfer Details" groups="stock.group_stock_user" type="object" class="oe_highlight" attrs="{'invisible': ['|',('pack_operation_exist', '=', True),('state','not in',('assigned', 'partially_available'))]}"/>
|
||||
<button name="open_barcode_interface" string="Open Barcode interface" groups="stock.group_stock_user" type="object" class="oe_highlight" attrs="{'invisible': ['|',('pack_operation_exist', '=', False),('state','not in',('assigned', 'partially_available'))]}"/>
|
||||
<button name="do_enter_transfer_details" states="assigned,partially_available" string="Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight"/>
|
||||
<button name="do_print_picking" string="Print Picking List" groups="stock.group_stock_user" type="object" attrs="{'invisible': ['|', ('picking_type_code', '=', 'outgoing'), ('state', '!=', 'assigned')]}"/>
|
||||
<button name="%(act_stock_return_picking)d" string="Reverse Transfer" states="done" type="action" groups="base.group_user"/>
|
||||
<button name="action_cancel" states="assigned,confirmed,partially_available,draft" string="Cancel Transfer" groups="base.group_user" type="object"/>
|
||||
|
@ -645,6 +643,8 @@
|
|||
</header>
|
||||
<sheet>
|
||||
<div class="oe_right oe_button_box">
|
||||
<button name="do_partial_open_barcode" groups="stock.group_stock_user" type="object" class="oe_stock_scan_button" attrs="{'invisible': ['|',('pack_operation_exist', '=', True),('state','not in',('assigned', 'partially_available'))]}"><img src="/stock/static/src/img/scan.png" class="oe_stock_scan_image oe_stock_scan_image_btn"/></button>
|
||||
<button name="open_barcode_interface" groups="stock.group_stock_user" type="object" class="oe_stock_scan_button" attrs="{'invisible': ['|',('pack_operation_exist', '=', False),('state','not in',('assigned', 'partially_available'))]}"><img src="/stock/static/src/img/scan.png" class="oe_stock_scan_image oe_stock_scan_image_btn"/></button>
|
||||
</div>
|
||||
<h1>
|
||||
<field name="name" class="oe_inline" attrs="{'invisible': [('name','=','/')]}" readonly="1"/>
|
||||
|
@ -673,20 +673,22 @@
|
|||
<field name="pack_operation_exist" invisible="1"/>
|
||||
<field name="note" placeholder="Add an internal note..." class="oe_inline"/>
|
||||
</page>
|
||||
<page string="Operations Done" attrs="{'invisible': ['|', ('state','!=','done'), ('pack_operation_ids','=',[])]}">
|
||||
<page string="Operations" attrs="{'invisible': ['|', ('state','!=','done'), ('pack_operation_ids','=',[])]}">
|
||||
<field name="pack_operation_ids">
|
||||
<tree editable="top">
|
||||
<field name="location_id"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_uom_id" groups="product.group_uom"/>
|
||||
<field name="lot_id" domain="[('product_id','=?', product_id)]" context="{'product_id': product_id}" groups="stock.group_production_lot"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="picking_id" invisible="1"/>
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
<field name="product_qty" attrs="{'required': [('product_id', '!=', False)]}"/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="result_package_id" groups="stock.group_tracking_lot"/>
|
||||
</tree>
|
||||
</field>
|
||||
<label class="oe_grey" string="Setting a product and a source package will result in a partial unpack of the source package (products will be taken out from that package). Set a source package without any product to move it as a whole."/>
|
||||
</page>
|
||||
<page string="Additional Info">
|
||||
<group string="General Informations">
|
||||
|
|
|
@ -24,4 +24,4 @@ import stock_return_picking
|
|||
import stock_change_product_qty
|
||||
import make_procurement_product
|
||||
import orderpoint_procurement
|
||||
|
||||
import stock_transfer_details
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-TODAY OpenERP S.A. <http://www.odoo.com>
|
||||
#
|
||||
# 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 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':{} }
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_stock_enter_transfer_details" model="ir.ui.view">
|
||||
<field name="name">Enter transfer details</field>
|
||||
<field name="model">stock.transfer_details</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Transfer details" version="7">
|
||||
<field name="picking_source_location_id" invisible="True"/>
|
||||
<field name="picking_destination_location_id" invisible="True"/>
|
||||
<field name="item_ids"
|
||||
context="{'default_sourceloc_id':picking_source_location_id,
|
||||
'default_destinationloc_id':picking_destination_location_id}">
|
||||
<tree string="Inventory Details" editable="bottom" >
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="product_id" required="True" context="{'uom':product_uom_id}" on_change="product_id_change(product_id,product_uom_id,context)"/>
|
||||
<field name="quantity"/>
|
||||
<button name="split_quantities" string="Split" type="object" icon="STOCK_PREFERENCES" attrs="{'invisible': [('quantity', '=', 1)]}"/>
|
||||
<field name="product_uom_id" options="{"no_open": True}" groups="product.group_uom"/>
|
||||
<field name="sourceloc_id" domain="[('id', 'child_of', parent.picking_source_location_id)]"/>
|
||||
<field name="destinationloc_id" domain="[('id', 'child_of', parent.picking_destination_location_id)]"/>
|
||||
<field name="result_package_id" groups="stock.group_tracking_lot" context="{'location_id': destinationloc_id}"/>
|
||||
<button name="put_in_pack" string="Pack" type="object" icon="terp-product" attrs="{'invisible': [('result_package_id', '!=', False)]}" groups="stock.group_tracking_lot"/>
|
||||
<field name="lot_id" groups="stock.group_production_lot" domain="[('product_id','=?', product_id)]" context="{'product_id': product_id}"/>
|
||||
</tree>
|
||||
</field>
|
||||
<label class="oe_grey" string="Setting a product and a source package will result in a partial unpack of the source package (products will be taken out from that package)."/>
|
||||
<field name="packop_ids" groups="stock.group_tracking_lot"
|
||||
context="{'default_sourceloc_id':picking_source_location_id,
|
||||
'default_destinationloc_id':picking_destination_location_id}">
|
||||
<tree editable="bottom">
|
||||
<field name="package_id" required="True" on_change="source_package_change(package_id)"/>
|
||||
<field name="sourceloc_id" domain="[('id', 'child_of', parent.picking_source_location_id)]"/>
|
||||
<field name="destinationloc_id" domain="[('id', 'child_of', parent.picking_destination_location_id)]"/>
|
||||
<field name="result_package_id"/>
|
||||
<button name="put_in_pack" string="Pack" type="object" icon="terp-product" attrs="{'invisible': [('result_package_id', '!=', False)]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
<footer>
|
||||
<button name="do_detailed_transfer" string="_Apply" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="_Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
Loading…
Reference in New Issue