mirror of
https://github.com/NaN-tic/trytond-stock_scanner.git
synced 2023-12-14 04:12:58 +01:00
Move POC picking to stock_scanner module. (#1)
Fix show last product. Now we order the pending moves by locations. If there are diferents locations, we show the name before the move. Fix picking more than one unit at the same time. 046607
This commit is contained in:
parent
ec21c45a65
commit
94f2fca489
8 changed files with 251 additions and 6 deletions
|
@ -2,6 +2,7 @@
|
|||
# copyright notices and license terms.
|
||||
from trytond.pool import Pool
|
||||
from . import stock
|
||||
from . import picking
|
||||
|
||||
|
||||
def register():
|
||||
|
@ -11,4 +12,10 @@ def register():
|
|||
stock.ShipmentIn,
|
||||
stock.ShipmentOut,
|
||||
stock.ShipmentOutReturn,
|
||||
picking.StockPickingShipmentOutAsk,
|
||||
picking.StockPickingShipmentOutScan,
|
||||
picking.StockPickingShipmentOutResult,
|
||||
module='stock_scanner', type_='model')
|
||||
Pool.register(
|
||||
picking.StockPickingShipmentOut,
|
||||
module='stock_scanner', type_='wizard')
|
161
picking.py
Normal file
161
picking.py
Normal file
|
@ -0,0 +1,161 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
from trytond.model import ModelView, fields
|
||||
from trytond.wizard import Wizard, StateTransition, StateView, Button
|
||||
from trytond.pool import Pool
|
||||
|
||||
|
||||
class StockPickingShipmentOutAsk(ModelView):
|
||||
'Stock Picking Shipment Out Ask'
|
||||
__name__ = 'stock.picking.shipment.out.ask'
|
||||
shipment = fields.Char('Shipment')
|
||||
to_pick = fields.Selection('get_to_pick', 'To Pick', sort=True)
|
||||
|
||||
@classmethod
|
||||
def get_to_pick(cls):
|
||||
pool = Pool()
|
||||
Shipment = pool.get('stock.shipment.out')
|
||||
return [(s.id, s.rec_name) for s in Shipment.search([
|
||||
('state', '=', 'assigned'),
|
||||
])]
|
||||
|
||||
|
||||
class StockPickingShipmentOutScan(ModelView):
|
||||
'Stock Picking Shipment Out Scan'
|
||||
__name__ = 'stock.picking.shipment.out.scan'
|
||||
shipment = fields.Many2One('stock.shipment.out', 'Shipment', readonly=True)
|
||||
product = fields.Many2One('product.product', 'Product', readonly=True)
|
||||
to_pick = fields.Char('To pick')
|
||||
pending_moves = fields.Text('APP Pending Moves', readonly=True)
|
||||
|
||||
|
||||
class StockPickingShipmentOutResult(ModelView):
|
||||
"Stock Picking Shipment Out Result"
|
||||
__name__ = 'stock.picking.shipment.out.result'
|
||||
shipment = fields.Many2One('stock.shipment.out', 'Shipment', readonly=True)
|
||||
note = fields.Text('Note', readonly=True)
|
||||
|
||||
|
||||
class StockPickingShipmentOut(Wizard):
|
||||
"Stock Picking Shipment Out Ask"
|
||||
__name__ = 'stock.picking.shipment.out'
|
||||
start_state = 'ask'
|
||||
ask = StateView('stock.picking.shipment.out.ask',
|
||||
'stock_scanner.stock_picking_shipment_out_start', [
|
||||
Button('Cancel', 'end', 'tryton-cancel'),
|
||||
Button('Scan', 'scan', 'tryton-ok', True),
|
||||
])
|
||||
scan = StateView('stock.picking.shipment.out.scan',
|
||||
'stock_scanner.stock_picking_shipment_out_scan', [
|
||||
Button('Cancel', 'end', 'tryton-cancel'),
|
||||
Button('Back', 'ask', 'tryton-back'),
|
||||
Button('Pick', 'pick', 'tryton-launch', True),
|
||||
Button('Packed', 'packed', 'tryton-ok'),
|
||||
])
|
||||
pick = StateTransition()
|
||||
packed = StateTransition()
|
||||
result = StateView('stock.picking.shipment.out.result',
|
||||
'stock_scanner.stock_picking_shipment_out_result', [
|
||||
Button('Start', 'ask', 'tryton-back', True),
|
||||
Button('Done', 'end', 'tryton-ok'),
|
||||
])
|
||||
|
||||
def transition_pick(self):
|
||||
pool = Pool()
|
||||
Shipment = pool.get('stock.shipment.out')
|
||||
|
||||
shipment = Shipment(self.scan.shipment)
|
||||
|
||||
def qty(value):
|
||||
try:
|
||||
return float(value)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
shipment = Shipment(self.scan.shipment)
|
||||
to_pick = self.scan.to_pick
|
||||
quantity = qty(to_pick)
|
||||
|
||||
if shipment.scanned_product and quantity and len(to_pick) < 5:
|
||||
shipment.scanned_quantity = shipment.scanned_uom.round(quantity)
|
||||
shipment.save()
|
||||
Shipment.scan([shipment])
|
||||
shipment = Shipment(shipment.id)
|
||||
else:
|
||||
for move in shipment.pending_moves:
|
||||
if move.matches_scan(to_pick):
|
||||
self.scan.product = move.product
|
||||
shipment.scanned_product = move.product
|
||||
shipment.scanned_quantity = 1
|
||||
shipment.on_change_scanned_product()
|
||||
shipment.save()
|
||||
Shipment.scan([shipment])
|
||||
shipment.scanned_product = move.product
|
||||
shipment.save()
|
||||
break
|
||||
else:
|
||||
self.scan.product = None
|
||||
return 'scan'
|
||||
|
||||
def transition_packed(self):
|
||||
pool = Pool()
|
||||
Shipment = pool.get('stock.shipment.out')
|
||||
|
||||
shipment = Shipment(self.scan.shipment)
|
||||
Shipment.assign([shipment])
|
||||
Shipment.pack([shipment])
|
||||
|
||||
return 'result'
|
||||
|
||||
def default_scan(self, fields):
|
||||
pool = Pool()
|
||||
Shipment = pool.get('stock.shipment.out')
|
||||
Location = pool.get('stock.location')
|
||||
|
||||
# Get storage_location locations
|
||||
storages = Location.search([('type', '=', 'warehouse')])
|
||||
storage_locations = []
|
||||
for storage in storages:
|
||||
storage_locations.append(storage.storage_location)
|
||||
|
||||
if self.ask.to_pick is not None:
|
||||
shipment = Shipment(self.ask.to_pick)
|
||||
else:
|
||||
shipments = Shipment.search([
|
||||
('state', '=', 'assigned'),
|
||||
('number', '=', self.ask.shipment),
|
||||
], limit=1)
|
||||
if not shipments:
|
||||
return {}
|
||||
shipment, = shipments
|
||||
|
||||
defaults = {}
|
||||
defaults['shipment'] = shipment.id
|
||||
if hasattr(self.scan, 'product'):
|
||||
defaults['product'] = self.scan.product and self.scan.product.id
|
||||
|
||||
pending_moves = []
|
||||
locations_move = {}
|
||||
for move in shipment.pending_moves:
|
||||
locations_move.setdefault(move.from_location, [])
|
||||
locations_move[move.from_location].append(move)
|
||||
|
||||
for location in sorted(locations_move, key=lambda x: x.name):
|
||||
if location not in storage_locations:
|
||||
pending_moves.append(
|
||||
u'<div align="left">'
|
||||
'<font size="4"><u><b>{}</b></u></font>'
|
||||
'</div>'.format(location.name))
|
||||
for move in locations_move[location]:
|
||||
pending_moves.append(
|
||||
u'<div align="left">'
|
||||
'<font size="4">{} <b>{}</b></font>'
|
||||
'</div>'.format(move.pending_quantity,
|
||||
move.product.rec_name))
|
||||
defaults['pending_moves'] = '\n'.join(pending_moves)
|
||||
return defaults
|
||||
|
||||
def default_result(self, fields):
|
||||
defaults = {}
|
||||
defaults['shipment'] = self.scan.shipment and self.scan.shipment.id
|
||||
return defaults
|
33
picking.xml
Normal file
33
picking.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part uudgore module for Tryton.
|
||||
The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<!-- Stock Picking Shipment Out-->
|
||||
<record model="ir.ui.view" id="stock_picking_shipment_out_start">
|
||||
<field name="model">stock.picking.shipment.out.ask</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">stock_picking_shipment_out_start</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="stock_picking_shipment_out_scan">
|
||||
<field name="model">stock.picking.shipment.out.scan</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">stock_picking_shipment_out_scan</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="stock_picking_shipment_out_result">
|
||||
<field name="model">stock.picking.shipment.out.result</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">stock_picking_shipment_out_result</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.wizard" id="act_stock_picking_shipment_out">
|
||||
<field name="name">Shipment Out Picking</field>
|
||||
<field name="wiz_name">stock.picking.shipment.out</field>
|
||||
<field name="window" eval="False"/>
|
||||
</record>
|
||||
<menuitem name="Shipment Out Picking" parent="stock.menu_shipment_out_form"
|
||||
action="act_stock_picking_shipment_out"
|
||||
id="menu_stock_shipment_out_picking"
|
||||
sequence="50"/>
|
||||
</data>
|
||||
</tryton>
|
25
stock.py
25
stock.py
|
@ -15,7 +15,7 @@ __all__ = ['Configuration', 'Move', 'ShipmentIn',
|
|||
|
||||
|
||||
MIXIN_STATES = {
|
||||
'readonly': ~Eval('state').in_(['waiting', 'draft']),
|
||||
'readonly': ~Eval('state').in_(['waiting', 'draft', 'assigned']),
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,6 +102,14 @@ class Move(metaclass=PoolMeta):
|
|||
'scanned_quantity': cls.default_scanned_quantity(),
|
||||
})
|
||||
|
||||
def matches_scan(self, input_):
|
||||
if self.product.code == input_:
|
||||
return True
|
||||
for identifier in self.product.identifiers:
|
||||
if identifier.code == input_:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class StockScanMixin(object):
|
||||
scanner_enabled = fields.Function(fields.Boolean('Scanner Enabled'),
|
||||
|
@ -109,7 +117,8 @@ class StockScanMixin(object):
|
|||
pending_moves = fields.Function(fields.One2Many('stock.move', None,
|
||||
'Pending Moves', states={
|
||||
'invisible': (~Eval('scanner_enabled', False)
|
||||
| ~Eval('state', 'draft').in_(['waiting', 'draft'])),
|
||||
| ~Eval('state', 'draft').in_(['waiting', 'draft',
|
||||
'assigned'])),
|
||||
}, depends=['scanner_enabled', 'state'],
|
||||
help='List of pending products to be scan.'),
|
||||
'get_pending_moves')
|
||||
|
@ -147,11 +156,13 @@ class StockScanMixin(object):
|
|||
},
|
||||
'reset_scanned_quantities': {
|
||||
'icon': 'tryton-refresh',
|
||||
'invisible': ~Eval('state').in_(['waiting', 'draft'])
|
||||
'invisible': ~Eval('state').in_(['waiting', 'draft',
|
||||
'assigned'])
|
||||
},
|
||||
'scan_all': {
|
||||
'icon': 'tryton-warning',
|
||||
'invisible': ~Eval('state').in_(['waiting', 'draft'])
|
||||
'invisible': ~Eval('state').in_(['waiting', 'draft',
|
||||
'assigned'])
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -382,9 +393,11 @@ class ShipmentOut(StockScanMixin, metaclass=PoolMeta):
|
|||
return move
|
||||
|
||||
@classmethod
|
||||
def assign_try(cls, shipments):
|
||||
def pack(cls, shipments):
|
||||
cls.wait(shipments)
|
||||
cls.set_scanned_quantity_as_quantity(shipments, 'inventory_moves')
|
||||
return super(ShipmentOut, cls).assign_try(shipments)
|
||||
cls.assign_try(shipments)
|
||||
return super(ShipmentOut, cls).pack(shipments)
|
||||
|
||||
|
||||
class ShipmentOutReturn(ShipmentOut, metaclass=PoolMeta):
|
||||
|
|
|
@ -8,4 +8,5 @@ extras_depend:
|
|||
stock_valued
|
||||
xml:
|
||||
message.xml
|
||||
picking.xml
|
||||
stock.xml
|
||||
|
|
12
view/stock_picking_shipment_out_result.xml
Normal file
12
view/stock_picking_shipment_out_result.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part stock_picking module for Tryton.
|
||||
The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
|
||||
<form>
|
||||
<image name="tryton-info" xexpand="0" xfill="0"/>
|
||||
<label string="Done picking shipment" id="packed" yalign="0.0" xalign="0.0" xexpand="1"/>
|
||||
<newline/>
|
||||
<label name="shipment"/>
|
||||
<field name="shipment"/>
|
||||
<newline/>
|
||||
<field name="note" colspan="6"/>
|
||||
</form>
|
9
view/stock_picking_shipment_out_scan.xml
Normal file
9
view/stock_picking_shipment_out_scan.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part stock_picking module for Tryton.
|
||||
The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
|
||||
<form col="4" cursor="to_pick">
|
||||
<field name="shipment" colspan="4"/>
|
||||
<field name="product" colspan="4"/>
|
||||
<field name="to_pick" colspan="4"/>
|
||||
<field name="pending_moves" colspan="4" widget="richtext" toolbar="0" yexpand="1" yfill="1"/>
|
||||
</form>
|
9
view/stock_picking_shipment_out_start.xml
Normal file
9
view/stock_picking_shipment_out_start.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part stock_picking module for Tryton.
|
||||
The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
|
||||
<form col="6">
|
||||
<label name="shipment"/>
|
||||
<field name="shipment"/>
|
||||
<label name="to_pick"/>
|
||||
<field name="to_pick"/>
|
||||
</form>
|
Loading…
Reference in a new issue