Use Workflow for Stock Move
review600002
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
* Add workflow to stock move
|
||||
|
||||
Version 2.6.0 - 2012-10-22
|
||||
* Bug fixes (see mercurial logs for details)
|
||||
* Add Product Quantities By Warehouse
|
||||
|
||||
+2
-4
@@ -263,9 +263,7 @@ class InventoryLine(ModelSQL, ModelView):
|
||||
@classmethod
|
||||
def cancel_move(cls, lines):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([l.move for l in lines if l.move], {
|
||||
'state': 'cancel',
|
||||
})
|
||||
Move.cancel([l.move for l in lines if l.move])
|
||||
Move.delete([l.move for l in lines if l.move])
|
||||
cls.write([l for l in lines if l.move], {
|
||||
'move': None,
|
||||
@@ -297,9 +295,9 @@ class InventoryLine(ModelSQL, ModelView):
|
||||
'product': self.product.id,
|
||||
'uom': self.uom.id,
|
||||
'company': self.inventory.company.id,
|
||||
'state': 'done',
|
||||
'effective_date': self.inventory.date,
|
||||
})
|
||||
Move.do([move])
|
||||
self.move = move
|
||||
self.save()
|
||||
return move.id
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from decimal import Decimal
|
||||
from functools import reduce
|
||||
from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.model import Workflow, ModelView, ModelSQL, fields
|
||||
from trytond.backend import TableHandler
|
||||
from trytond.pyson import In, Eval, Not, Equal, If, Get, Bool
|
||||
from trytond.transaction import Transaction
|
||||
@@ -16,7 +16,7 @@ STATES = {
|
||||
DEPENDS = ['state']
|
||||
|
||||
|
||||
class Move(ModelSQL, ModelView):
|
||||
class Move(Workflow, ModelSQL, ModelView):
|
||||
"Stock Move"
|
||||
__name__ = 'stock.move'
|
||||
_order_name = 'product'
|
||||
@@ -149,6 +149,28 @@ class Move(ModelSQL, ModelView):
|
||||
'modify_assigned_done_cancel': ('You can not modify a move '
|
||||
'in the state: "Assigned", "Done" or "Cancel"'),
|
||||
})
|
||||
cls._transitions |= set((
|
||||
('draft', 'assigned'),
|
||||
('draft', 'done'),
|
||||
('draft', 'cancel'),
|
||||
('assigned', 'draft'),
|
||||
('assigned', 'done'),
|
||||
('assigned', 'cancel'),
|
||||
))
|
||||
cls._buttons.update({
|
||||
'cancel': {
|
||||
'invisible': ~Eval('state').in_(['draft', 'assigned']),
|
||||
},
|
||||
'draft': {
|
||||
'invisible': ~Eval('state').in_(['assigned']),
|
||||
},
|
||||
'assign': {
|
||||
'invisible': ~Eval('state').in_(['assigned']),
|
||||
},
|
||||
'do': {
|
||||
'invisible': ~Eval('state').in_(['draft', 'assigned']),
|
||||
},
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
@@ -306,13 +328,10 @@ class Move(ModelSQL, ModelView):
|
||||
def search_rec_name(cls, name, clause):
|
||||
return [('product',) + clause[1:]]
|
||||
|
||||
@classmethod
|
||||
def _update_product_cost_price(cls, product_id, quantity, uom, unit_price,
|
||||
currency, company, date):
|
||||
def _update_product_cost_price(self, direction):
|
||||
"""
|
||||
Update the cost price on the given product.
|
||||
The quantity must be positive if incoming and negative if outgoing.
|
||||
The date is for the currency rate calculation.
|
||||
The direction must be "in" if incoming and "out" if outgoing.
|
||||
"""
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
@@ -320,24 +339,20 @@ class Move(ModelSQL, ModelView):
|
||||
ProductTemplate = pool.get('product.template')
|
||||
Location = pool.get('stock.location')
|
||||
Currency = pool.get('currency.currency')
|
||||
Company = pool.get('company.company')
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
if isinstance(uom, (int, long)):
|
||||
uom = Uom(uom)
|
||||
if isinstance(currency, (int, long)):
|
||||
currency = Currency(currency)
|
||||
if isinstance(company, (int, long)):
|
||||
company = Company(company)
|
||||
|
||||
if direction == 'in':
|
||||
quantity = self.quantity
|
||||
elif direction == 'out':
|
||||
quantity = -self.quantity
|
||||
context = {}
|
||||
context['locations'] = Location.search([
|
||||
('type', '=', 'storage'),
|
||||
])
|
||||
context['stock_date_end'] = Date.today()
|
||||
with Transaction().set_context(context):
|
||||
product = Product(product_id)
|
||||
qty = Uom.compute_qty(uom, quantity, product.default_uom)
|
||||
product = Product(self.product.id)
|
||||
qty = Uom.compute_qty(self.uom, quantity, product.default_uom)
|
||||
|
||||
qty = Decimal(str(qty))
|
||||
if hasattr(Product, 'cost_price'):
|
||||
@@ -346,11 +361,12 @@ class Move(ModelSQL, ModelView):
|
||||
product_qty = product.template.quantity
|
||||
product_qty = Decimal(str(product_qty))
|
||||
# convert wrt currency
|
||||
with Transaction().set_context(date=date):
|
||||
unit_price = Currency.compute(currency, unit_price,
|
||||
company.currency, round=False)
|
||||
with Transaction().set_context(date=self.effective_date):
|
||||
unit_price = Currency.compute(self.currency, self.unit_price,
|
||||
self.company.currency, round=False)
|
||||
# convert wrt to the uom
|
||||
unit_price = Uom.compute_price(uom, unit_price, product.default_uom)
|
||||
unit_price = Uom.compute_price(self.uom, unit_price,
|
||||
product.default_uom)
|
||||
if product_qty + qty != Decimal('0.0'):
|
||||
new_cost_price = (
|
||||
(product.cost_price * product_qty) + (unit_price * qty)
|
||||
@@ -378,44 +394,78 @@ class Move(ModelSQL, ModelView):
|
||||
return internal_quantity
|
||||
|
||||
@classmethod
|
||||
def create(cls, vals):
|
||||
@ModelView.button
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, moves):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('assigned')
|
||||
def assign(cls, moves):
|
||||
pool = Pool()
|
||||
Location = pool.get('stock.location')
|
||||
Product = pool.get('product.product')
|
||||
Uom = pool.get('product.uom')
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
today = Date.today()
|
||||
for move in moves:
|
||||
if not move.effective_date:
|
||||
move.effective_date = today
|
||||
move.save()
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('done')
|
||||
def do(cls, moves):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
today = Date.today()
|
||||
for move in moves:
|
||||
if not move.effective_date:
|
||||
move.effective_date = today
|
||||
if (move.from_location.type in ('supplier', 'production')
|
||||
and move.to_location.type == 'storage'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
move._update_product_cost_price('in')
|
||||
elif (move.to_location.type == 'supplier'
|
||||
and move.from_location.type == 'storage'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
move._update_product_cost_price('out')
|
||||
if not move.cost_price:
|
||||
move.cost_price = move.product.cost_price
|
||||
move.save()
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, moves):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
today = Date.today()
|
||||
for move in moves:
|
||||
move.effective_date = today
|
||||
if (move.from_location.type in ('supplier', 'production')
|
||||
and move.to_location.type == 'storage'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
move._update_product_cost_price('out')
|
||||
elif (move.to_location.type == 'supplier'
|
||||
and move.from_location.type == 'storage'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
move._update_product_cost_price('in')
|
||||
move.effective_date = None
|
||||
move.save()
|
||||
|
||||
@classmethod
|
||||
def create(cls, vals):
|
||||
pool = Pool()
|
||||
Product = pool.get('product.product')
|
||||
Uom = pool.get('product.uom')
|
||||
|
||||
assert vals.get('state', 'draft') == 'draft'
|
||||
vals = vals.copy()
|
||||
effective_date = vals.get('effective_date') or today
|
||||
|
||||
product = Product(vals['product'])
|
||||
if vals.get('state') == 'done':
|
||||
vals['effective_date'] = effective_date
|
||||
currency_id = vals.get('currency', cls.default_currency())
|
||||
company_id = vals.get('company', cls.default_company())
|
||||
from_location = Location(vals['from_location'])
|
||||
to_location = Location(vals['to_location'])
|
||||
if (from_location.type in ('supplier', 'production')
|
||||
and to_location.type == 'storage'
|
||||
and product.cost_price_method == 'average'):
|
||||
cls._update_product_cost_price(vals['product'],
|
||||
vals['quantity'], vals['uom'], vals['unit_price'],
|
||||
currency_id, company_id, effective_date)
|
||||
if (to_location.type == 'supplier'
|
||||
and from_location.type == 'storage'
|
||||
and product.cost_price_method == 'average'):
|
||||
cls._update_product_cost_price(vals['product'],
|
||||
-vals['quantity'], vals['uom'], vals['unit_price'],
|
||||
currency_id, company_id, effective_date)
|
||||
if not vals.get('cost_price'):
|
||||
# Re-read product to get the updated cost_price
|
||||
product = Product(vals['product'])
|
||||
vals['cost_price'] = product.cost_price
|
||||
|
||||
elif vals.get('state') == 'assigned':
|
||||
vals['effective_date'] = effective_date
|
||||
|
||||
uom = Uom(vals['uom'])
|
||||
internal_quantity = cls._get_internal_quantity(vals['quantity'],
|
||||
uom, product)
|
||||
@@ -424,57 +474,6 @@ class Move(ModelSQL, ModelView):
|
||||
|
||||
@classmethod
|
||||
def write(cls, moves, vals):
|
||||
Date = Pool().get('ir.date')
|
||||
|
||||
today = Date.today()
|
||||
effective_date = vals.get('effective_date') or today
|
||||
|
||||
if 'state' in vals:
|
||||
for move in moves:
|
||||
if vals['state'] == 'cancel':
|
||||
vals['effective_date'] = None
|
||||
if (move.from_location.type in ('supplier', 'production')
|
||||
and move.to_location.type == 'storage'
|
||||
and move.state != 'cancel'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
cls._update_product_cost_price(move.product.id,
|
||||
-move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company, today)
|
||||
if (move.to_location.type == 'supplier'
|
||||
and move.from_location.type == 'storage'
|
||||
and move.state != 'cancel'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
cls._update_product_cost_price(move.product.id,
|
||||
move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company, today)
|
||||
|
||||
elif vals['state'] == 'draft':
|
||||
if move.state == 'done':
|
||||
cls.raise_user_error('set_state_draft')
|
||||
elif vals['state'] == 'assigned':
|
||||
if move.state in ('cancel', 'done'):
|
||||
cls.raise_user_error('set_state_assigned')
|
||||
vals['effective_date'] = effective_date
|
||||
elif vals['state'] == 'done':
|
||||
if move.state in ('cancel'):
|
||||
cls.raise_user_error('set_state_done')
|
||||
vals['effective_date'] = effective_date
|
||||
|
||||
if (move.from_location.type in ('supplier', 'production')
|
||||
and move.to_location.type == 'storage'
|
||||
and move.state != 'done'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
cls._update_product_cost_price(move.product.id,
|
||||
move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company, effective_date)
|
||||
if (move.to_location.type == 'supplier'
|
||||
and move.from_location.type == 'storage'
|
||||
and move.state != 'done'
|
||||
and move.product.cost_price_method == 'average'):
|
||||
cls._update_product_cost_price(move.product.id,
|
||||
-move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company, effective_date)
|
||||
|
||||
if reduce(lambda x, y: x or y in vals, ('product', 'uom', 'quantity',
|
||||
'from_location', 'to_location', 'company', 'unit_price',
|
||||
'currency'), False):
|
||||
@@ -482,26 +481,18 @@ class Move(ModelSQL, ModelView):
|
||||
if move.state in ('assigned', 'done', 'cancel'):
|
||||
cls.raise_user_error('modify_assigned_done_cancel')
|
||||
if reduce(lambda x, y: x or y in vals,
|
||||
('planned_date', 'effective_date'), False):
|
||||
('planned_date', 'effective_date', 'state'), False):
|
||||
for move in moves:
|
||||
if move.state in ('done', 'cancel'):
|
||||
cls.raise_user_error('modify_assigned_done_cancel')
|
||||
|
||||
super(Move, cls).write(moves, vals)
|
||||
|
||||
if vals.get('state', '') == 'done':
|
||||
for move in moves:
|
||||
if not move.cost_price:
|
||||
cls.write([move], {
|
||||
'cost_price': move.product.cost_price,
|
||||
})
|
||||
|
||||
for move in moves:
|
||||
internal_quantity = cls._get_internal_quantity(move.quantity,
|
||||
move.uom, move.product)
|
||||
if internal_quantity != move.internal_quantity:
|
||||
# Use super to avoid infinite loop
|
||||
super(Move, cls).write([move], {
|
||||
cls.write([move], {
|
||||
'internal_quantity': internal_quantity,
|
||||
})
|
||||
|
||||
@@ -595,13 +586,13 @@ class Move(ModelSQL, ModelView):
|
||||
values = {
|
||||
'from_location': from_location.id,
|
||||
'quantity': qty,
|
||||
'state': 'assigned',
|
||||
}
|
||||
if first:
|
||||
cls.write([move], values)
|
||||
cls.assign([move])
|
||||
first = False
|
||||
else:
|
||||
cls.copy([move], default=values)
|
||||
cls.assign(cls.copy([move], default=values))
|
||||
|
||||
qty_default_uom = Uom.compute_qty(move.uom, qty,
|
||||
move.product.default_uom, round=False)
|
||||
|
||||
+30
-105
@@ -390,21 +390,15 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments
|
||||
for m in s.incoming_moves + s.inventory_moves
|
||||
if m.state not in ('cancel', 'done')], {
|
||||
'state': 'cancel',
|
||||
})
|
||||
Move.cancel([m for s in shipments
|
||||
for m in s.incoming_moves + s.inventory_moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.incoming_moves
|
||||
if m.state not in ('draft', 'done')], {
|
||||
'state': 'draft',
|
||||
})
|
||||
Move.draft([m for s in shipments for m in s.incoming_moves])
|
||||
Move.delete([m for s in shipments for m in s.inventory_moves
|
||||
if m.state in ('draft', 'cancel')])
|
||||
|
||||
@@ -413,10 +407,7 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('received')
|
||||
def receive(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.incoming_moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.incoming_moves])
|
||||
cls.create_inventory_moves(shipments)
|
||||
|
||||
@classmethod
|
||||
@@ -426,10 +417,7 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
Date = pool.get('ir.date')
|
||||
Move.write([m for s in shipments for m in s.inventory_moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.inventory_moves])
|
||||
cls.write(shipments, {
|
||||
'effective_date': Date.today(),
|
||||
})
|
||||
@@ -641,10 +629,7 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('draft', 'done')], {
|
||||
'state': 'draft',
|
||||
})
|
||||
Move.draft([m for s in shipments for m in s.moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@@ -652,20 +637,14 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
|
||||
def wait(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
for shipment in shipments:
|
||||
Move.write([m for m in shipment.moves
|
||||
if m.state not in ('cancel', 'draft', 'done')], {
|
||||
'state': 'draft',
|
||||
'planned_date': shipment._move_planned_date,
|
||||
})
|
||||
Move.draft([m for m in shipment.moves])
|
||||
cls._set_move_planned_date(shipments)
|
||||
|
||||
@classmethod
|
||||
@Workflow.transition('assigned')
|
||||
def assign(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('assigned', 'cancel', 'done')], {
|
||||
'state': 'assigned',
|
||||
})
|
||||
Move.assign([m for s in shipments for m in s.moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@@ -675,10 +654,7 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
|
||||
Move = pool.get('stock.move')
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.moves])
|
||||
cls.write(shipments, {
|
||||
'effective_date': Date.today(),
|
||||
})
|
||||
@@ -688,10 +664,7 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('cancel', 'done')], {
|
||||
'state': 'cancel',
|
||||
})
|
||||
Move.cancel([m for s in shipments for m in s.moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button_action('stock.wizard_shipment_in_return_assign')
|
||||
@@ -1014,11 +987,8 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments
|
||||
for m in s.inventory_moves + s.outgoing_moves
|
||||
if m.state not in ('draft', 'done')], {
|
||||
'state': 'draft',
|
||||
})
|
||||
Move.draft([m for s in shipments
|
||||
for m in s.inventory_moves + s.outgoing_moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@@ -1030,10 +1000,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
|
||||
"""
|
||||
Move = Pool().get('stock.move')
|
||||
|
||||
Move.write([m for s in shipments for m in s.inventory_moves
|
||||
if m.state not in ('draft', 'done')], {
|
||||
'state': 'draft',
|
||||
})
|
||||
Move.draft([m for s in shipments for m in s.inventory_moves])
|
||||
Move.delete([m for s in shipments for m in s.inventory_moves
|
||||
if m.state in ('draft', 'cancel')])
|
||||
|
||||
@@ -1068,10 +1035,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
Uom = pool.get('product.uom')
|
||||
Move.write([m for s in shipments for m in s.inventory_moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.inventory_moves])
|
||||
|
||||
for shipment in shipments:
|
||||
# Sum all outgoing quantities
|
||||
@@ -1136,10 +1100,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
|
||||
})
|
||||
outgoing_qty[move.product.id] -= removed_qty
|
||||
|
||||
Move.write([m for s in shipments for m in s.outgoing_moves
|
||||
if m.state not in ('cancel', 'done')], {
|
||||
'state': 'assigned',
|
||||
})
|
||||
Move.assign([m for s in shipments for m in s.outgoing_moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@@ -1149,10 +1110,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
|
||||
Move = pool.get('stock.move')
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
Move.write([m for s in shipments for m in s.outgoing_moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.outgoing_moves])
|
||||
cls.write(shipments, {
|
||||
'effective_date': Date.today(),
|
||||
})
|
||||
@@ -1162,11 +1120,8 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments
|
||||
for m in s.outgoing_moves + s.inventory_moves
|
||||
if m.state not in ('cancel', 'done')], {
|
||||
'state': 'cancel',
|
||||
})
|
||||
Move.cancel([m for s in shipments
|
||||
for m in s.outgoing_moves + s.inventory_moves])
|
||||
|
||||
@property
|
||||
def _move_planned_date(self):
|
||||
@@ -1263,10 +1218,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
|
||||
@ModelView.button
|
||||
def assign_force(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.inventory_moves
|
||||
if m.state not in ('cancel', 'done')], {
|
||||
'state': 'assigned',
|
||||
})
|
||||
Move.assign([m for s in shipments for m in s.inventory_moves])
|
||||
cls.assign(shipments)
|
||||
|
||||
|
||||
@@ -1580,10 +1532,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.incoming_moves
|
||||
if m.state not in ('draft', 'done')], {
|
||||
'state': 'draft',
|
||||
})
|
||||
Move.draft([m for s in shipments for m in s.incoming_moves])
|
||||
Move.delete([m for s in shipments for m in s.inventory_moves
|
||||
if m.state in ('draft', 'cancel')])
|
||||
|
||||
@@ -1592,10 +1541,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('received')
|
||||
def receive(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.incoming_moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.incoming_moves])
|
||||
cls.create_inventory_moves(shipments)
|
||||
|
||||
@classmethod
|
||||
@@ -1605,10 +1551,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
Date = pool.get('ir.date')
|
||||
Move.write([m for s in shipments for m in s.inventory_moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.inventory_moves])
|
||||
cls.write(shipments, {
|
||||
'effective_date': Date.today(),
|
||||
})
|
||||
@@ -1618,11 +1561,8 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments
|
||||
for m in s.incoming_moves + s.inventory_moves
|
||||
if m.state not in ('cancel', 'done')], {
|
||||
'state': 'cancel',
|
||||
})
|
||||
Move.cancel([m for s in shipments
|
||||
for m in s.incoming_moves + s.inventory_moves])
|
||||
|
||||
@staticmethod
|
||||
def _get_inventory_moves(incoming_move):
|
||||
@@ -1893,10 +1833,7 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('draft')
|
||||
def draft(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('draft', 'done')], {
|
||||
'state': 'draft',
|
||||
})
|
||||
Move.draft([m for s in shipments for m in s.moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@@ -1904,10 +1841,7 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
|
||||
def wait(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
# First reset state to draft to allow update from and to location
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('draft', 'done')], {
|
||||
'state': 'draft',
|
||||
})
|
||||
Move.draft([m for s in shipments for m in s.moves])
|
||||
for shipment in shipments:
|
||||
Move.write([m for m in shipment.moves
|
||||
if m.state != 'done'], {
|
||||
@@ -1928,10 +1862,7 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
Date = pool.get('ir.date')
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('done', 'cancel')], {
|
||||
'state': 'done',
|
||||
})
|
||||
Move.do([m for s in shipments for m in s.moves])
|
||||
cls.write(shipments, {
|
||||
'effective_date': Date.today(),
|
||||
})
|
||||
@@ -1941,10 +1872,7 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
|
||||
@Workflow.transition('cancel')
|
||||
def cancel(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('cancel', 'done')], {
|
||||
'state': 'cancel',
|
||||
})
|
||||
Move.cancel([m for s in shipments for m in s.moves])
|
||||
|
||||
@classmethod
|
||||
@ModelView.button_action('stock.wizard_shipment_internal_assign')
|
||||
@@ -1966,10 +1894,7 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
|
||||
@ModelView.button
|
||||
def assign_force(cls, shipments):
|
||||
Move = Pool().get('stock.move')
|
||||
Move.write([m for s in shipments for m in s.moves
|
||||
if m.state not in ('assigned', 'done')], {
|
||||
'state': 'assigned',
|
||||
})
|
||||
Move.assign([m for s in shipments for m in s.moves])
|
||||
cls.assign(shipments)
|
||||
|
||||
|
||||
|
||||
@@ -132,11 +132,11 @@ Make 1 unit of the product available::
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.state = 'done'
|
||||
>>> incoming_move.company = company
|
||||
>>> incoming_move.unit_price = Decimal('1')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.save()
|
||||
>>> StockMove.do([incoming_move.id], config.context)
|
||||
|
||||
Assign the shipment now::
|
||||
|
||||
|
||||
+105
-118
@@ -136,19 +136,18 @@ class StockTestCase(unittest.TestCase):
|
||||
|
||||
today = datetime.date.today()
|
||||
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': kg.id,
|
||||
'quantity': 5,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': kg.id,
|
||||
'quantity': 5,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})])
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': kg.id,
|
||||
@@ -156,11 +155,22 @@ class StockTestCase(unittest.TestCase):
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-4),
|
||||
'state': 'draft',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': kg.id,
|
||||
'quantity': 1,
|
||||
'from_location': storage.id,
|
||||
'to_location': customer.id,
|
||||
'planned_date': today,
|
||||
'effective_date': today,
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})])
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': kg.id,
|
||||
@@ -168,20 +178,6 @@ class StockTestCase(unittest.TestCase):
|
||||
'from_location': storage.id,
|
||||
'to_location': customer.id,
|
||||
'planned_date': today,
|
||||
'effective_date': today,
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': kg.id,
|
||||
'quantity': 1,
|
||||
'from_location': storage.id,
|
||||
'to_location': customer.id,
|
||||
'planned_date': today,
|
||||
'state': 'draft',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
@@ -193,7 +189,6 @@ class StockTestCase(unittest.TestCase):
|
||||
'from_location': storage.id,
|
||||
'to_location': customer.id,
|
||||
'planned_date': today + relativedelta(days=5),
|
||||
'state': 'draft',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
@@ -205,7 +200,6 @@ class StockTestCase(unittest.TestCase):
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=7),
|
||||
'state': 'draft',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
@@ -293,19 +287,18 @@ class StockTestCase(unittest.TestCase):
|
||||
today + relativedelta(days=-2),
|
||||
]
|
||||
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': g.id,
|
||||
'quantity': 1,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': g.id,
|
||||
'quantity': 1,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})])
|
||||
# Nothing should change when adding a small quantity
|
||||
test_products_by_location()
|
||||
|
||||
@@ -355,17 +348,16 @@ class StockTestCase(unittest.TestCase):
|
||||
'parent': storage.id,
|
||||
})
|
||||
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 1,
|
||||
'from_location': lost_found.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today,
|
||||
'effective_date': today,
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
})
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 1,
|
||||
'from_location': lost_found.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today,
|
||||
'effective_date': today,
|
||||
'company': company.id,
|
||||
})])
|
||||
|
||||
products_by_location = self.product.products_by_location(
|
||||
[warehouse.id], [product.id], with_childs=True)
|
||||
@@ -402,45 +394,42 @@ class StockTestCase(unittest.TestCase):
|
||||
|
||||
today = datetime.date.today()
|
||||
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 10,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 15,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-4),
|
||||
'effective_date': today + relativedelta(days=-4),
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 5,
|
||||
'from_location': storage.id,
|
||||
'to_location': customer.id,
|
||||
'planned_date': today + relativedelta(days=-3),
|
||||
'effective_date': today + relativedelta(days=-3),
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 10,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})])
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 15,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-4),
|
||||
'effective_date': today + relativedelta(days=-4),
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})])
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 5,
|
||||
'from_location': storage.id,
|
||||
'to_location': customer.id,
|
||||
'planned_date': today + relativedelta(days=-3),
|
||||
'effective_date': today + relativedelta(days=-3),
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})])
|
||||
|
||||
tests = [
|
||||
(-5, {
|
||||
@@ -470,33 +459,31 @@ class StockTestCase(unittest.TestCase):
|
||||
quantities[cache.location.id])
|
||||
|
||||
# Test check_period_closed
|
||||
self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 10,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today,
|
||||
'effective_date': today,
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
self.move.do([self.move.create({
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 10,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today,
|
||||
'effective_date': today,
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})])
|
||||
|
||||
self.assertRaises(Exception, self.move.create, {
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 10,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'state': 'done',
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
'product': product.id,
|
||||
'uom': unit.id,
|
||||
'quantity': 10,
|
||||
'from_location': supplier.id,
|
||||
'to_location': storage.id,
|
||||
'planned_date': today + relativedelta(days=-5),
|
||||
'effective_date': today + relativedelta(days=-5),
|
||||
'company': company.id,
|
||||
'unit_price': Decimal('1'),
|
||||
'currency': currency.id,
|
||||
})
|
||||
|
||||
# Test close period check
|
||||
period = self.period.create({
|
||||
|
||||
Reference in New Issue
Block a user