Update for new Transaction
This commit is contained in:
@@ -4,7 +4,7 @@ Installing trytond_stock
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* Python 2.4 or later (http://www.python.org/)
|
||||
* Python 2.5 or later (http://www.python.org/)
|
||||
* trytond (http://www.tryton.org/)
|
||||
* trytond_party (http://www.tryton.org/)
|
||||
* trytond_product (http://www.tryton.org/)
|
||||
|
||||
+69
-93
@@ -1,10 +1,11 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level
|
||||
#of this repository contains the full copyright notices and license terms.
|
||||
'Inventory'
|
||||
from __future__ import with_statement
|
||||
from trytond.model import ModelWorkflow, ModelView, ModelSQL, fields
|
||||
from trytond.wizard import Wizard
|
||||
from trytond.pyson import Not, Equal, Eval, Or, Bool
|
||||
from trytond.backend import TableHandler
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
STATES = {
|
||||
'readonly': Not(Equal(Eval('state'), 'draft')),
|
||||
@@ -47,60 +48,56 @@ class Inventory(ModelWorkflow, ModelSQL, ModelView):
|
||||
super(Inventory, self).__init__()
|
||||
self._order.insert(0, ('date', 'DESC'))
|
||||
|
||||
def init(self, cursor, module_name):
|
||||
super(Inventory, self).init(cursor, module_name)
|
||||
def init(self, module_name):
|
||||
super(Inventory, self).init(module_name)
|
||||
cursor = Transaction().cursor
|
||||
|
||||
# Add index on create_date
|
||||
table = TableHandler(cursor, self, module_name)
|
||||
table.index_action('create_date', action='add')
|
||||
|
||||
def default_state(self, cursor, user, context=None):
|
||||
def default_state(self):
|
||||
return 'draft'
|
||||
|
||||
def default_date(self, cursor, user, context=None):
|
||||
def default_date(self):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
return date_obj.today(cursor, user, context=context)
|
||||
return date_obj.today()
|
||||
|
||||
def default_company(self, cursor, user, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if context.get('company'):
|
||||
return context['company']
|
||||
return False
|
||||
def default_company(self):
|
||||
return Transaction().context.get('company') or False
|
||||
|
||||
def default_lost_found(self, cursor, user, context=None):
|
||||
def default_lost_found(self):
|
||||
location_obj = self.pool.get('stock.location')
|
||||
location_ids = location_obj.search(cursor, user,
|
||||
self.lost_found.domain, context=context)
|
||||
location_ids = location_obj.search(self.lost_found.domain)
|
||||
if len(location_ids) == 1:
|
||||
return location_ids[0]
|
||||
return False
|
||||
|
||||
def set_state_draft(self, cursor, user, inventory_id, context=None):
|
||||
self.write(cursor, user, inventory_id, {
|
||||
def set_state_draft(self, inventory_id):
|
||||
self.write(inventory_id, {
|
||||
'state': 'draft',
|
||||
}, context=context)
|
||||
})
|
||||
|
||||
def set_state_cancel(self, cursor, user, inventory_id, context=None):
|
||||
def set_state_cancel(self, inventory_id):
|
||||
line_obj = self.pool.get("stock.inventory.line")
|
||||
inventory = self.browse(cursor, user, inventory_id, context=context)
|
||||
line_obj.cancel_move(cursor, user, inventory.lines, context=context)
|
||||
self.write(cursor, user, inventory_id, {
|
||||
inventory = self.browse(inventory_id)
|
||||
line_obj.cancel_move(inventory.lines)
|
||||
self.write(inventory_id, {
|
||||
'state': 'cancel',
|
||||
}, context=context)
|
||||
})
|
||||
|
||||
def set_state_done(self, cursor, user, inventory_id, context=None):
|
||||
def set_state_done(self, inventory_id):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
line_obj = self.pool.get('stock.inventory.line')
|
||||
inventory = self.browse(cursor, user, inventory_id, context=context)
|
||||
inventory = self.browse(inventory_id)
|
||||
|
||||
for line in inventory.lines:
|
||||
line_obj.create_move(cursor, user, line, context=context)
|
||||
self.write(cursor, user, inventory_id, {
|
||||
line_obj.create_move(line)
|
||||
self.write(inventory_id, {
|
||||
'state': 'done',
|
||||
}, context=context)
|
||||
})
|
||||
|
||||
def copy(self, cursor, user, ids, default=None, context=None):
|
||||
def copy(self, ids, default=None):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
line_obj = self.pool.get('stock.inventory.line')
|
||||
|
||||
@@ -112,31 +109,28 @@ class Inventory(ModelWorkflow, ModelSQL, ModelView):
|
||||
if default is None:
|
||||
default = {}
|
||||
default = default.copy()
|
||||
default['date'] = date_obj.today(cursor, user, context=context)
|
||||
default['date'] = date_obj.today()
|
||||
default['lines'] = False
|
||||
|
||||
new_ids = []
|
||||
for inventory in self.browse(cursor, user, ids, context=context):
|
||||
new_id = super(Inventory, self).copy(cursor, user, inventory.id,
|
||||
default=default, context=context)
|
||||
line_obj.copy(cursor, user, [x.id for x in inventory.lines],
|
||||
for inventory in self.browse(ids):
|
||||
new_id = super(Inventory, self).copy(inventory.id, default=default)
|
||||
line_obj.copy([x.id for x in inventory.lines],
|
||||
default={
|
||||
'inventory': new_id,
|
||||
'move': False,
|
||||
}, context=context)
|
||||
self.complete_lines(cursor, user, new_id, context=context)
|
||||
})
|
||||
self.complete_lines(new_id)
|
||||
new_ids.append(new_id)
|
||||
|
||||
if int_id:
|
||||
return new_ids[0]
|
||||
return new_ids
|
||||
|
||||
def complete_lines(self, cursor, user, ids, context=None):
|
||||
def complete_lines(self, ids):
|
||||
'''
|
||||
Complete or update the inventories
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param ids: the ids of stock.inventory
|
||||
:param context: the context
|
||||
'''
|
||||
@@ -147,22 +141,18 @@ class Inventory(ModelWorkflow, ModelSQL, ModelView):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
|
||||
inventories = self.browse(cursor, user, ids,
|
||||
context=context)
|
||||
context = context and context.copy() or {}
|
||||
inventories = self.browse(ids)
|
||||
|
||||
for inventory in inventories:
|
||||
# Compute product quantities
|
||||
ctx = context and context.copy() or {}
|
||||
ctx['stock_date_end'] = inventory.date
|
||||
pbl = product_obj.products_by_location(
|
||||
cursor, user, [inventory.location.id], context=ctx)
|
||||
with Transaction().set_context(stock_date_end=inventory.date):
|
||||
pbl = product_obj.products_by_location(
|
||||
[inventory.location.id])
|
||||
|
||||
# Index some data
|
||||
product2uom = {}
|
||||
product2type = {}
|
||||
for product in product_obj.browse(cursor, user,
|
||||
[line[1] for line in pbl], context=context):
|
||||
for product in product_obj.browse([line[1] for line in pbl]):
|
||||
product2uom[product.id] = product.default_uom.id
|
||||
product2type[product.id] = product.type
|
||||
|
||||
@@ -174,7 +164,7 @@ class Inventory(ModelWorkflow, ModelSQL, ModelView):
|
||||
for line in inventory.lines:
|
||||
if not (line.product.active and
|
||||
line.product.type == 'stockable'):
|
||||
line_obj.delete(cursor, user, line.id, context=context)
|
||||
line_obj.delete(line.id)
|
||||
continue
|
||||
if line.product.id in product_qty:
|
||||
quantity, uom_id = product_qty.pop(line.product.id)
|
||||
@@ -182,21 +172,18 @@ class Inventory(ModelWorkflow, ModelSQL, ModelView):
|
||||
quantity, uom_id = 0.0, product2uom[line.product.id]
|
||||
else:
|
||||
quantity, uom_id = 0.0, line.product.default_uom.id
|
||||
values = line_obj.update_values4complete(cursor, user,
|
||||
line, quantity, uom_id, context=context)
|
||||
values = line_obj.update_values4complete(line, quantity, uom_id)
|
||||
if values:
|
||||
line_obj.write(cursor, user, line.id, values,
|
||||
context=context)
|
||||
line_obj.write(line.id, values)
|
||||
|
||||
# Create lines if needed
|
||||
for product_id in product_qty:
|
||||
if product2type[product_id] != 'stockable':
|
||||
continue
|
||||
quantity, uom_id = product_qty[product_id]
|
||||
values = line_obj.create_values4complete(cursor, user,
|
||||
product_id, inventory, quantity, uom_id,
|
||||
context=context)
|
||||
line_obj.create(cursor, user, values, context=context)
|
||||
values = line_obj.create_values4complete(product_id, inventory,
|
||||
quantity, uom_id)
|
||||
line_obj.create(values)
|
||||
|
||||
Inventory()
|
||||
|
||||
@@ -231,53 +218,48 @@ class InventoryLine(ModelSQL, ModelView):
|
||||
]
|
||||
self._order.insert(0, ('product', 'ASC'))
|
||||
|
||||
def default_unit_digits(self, cursor, user, context=None):
|
||||
def default_unit_digits(self):
|
||||
return 2
|
||||
|
||||
def on_change_product(self, cursor, user, vals, context=None):
|
||||
def on_change_product(self, vals):
|
||||
product_obj = self.pool.get('product.product')
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
res = {}
|
||||
res['unit_digits'] = 2
|
||||
if vals.get('product'):
|
||||
product = product_obj.browse(cursor, user, vals['product'],
|
||||
context=context)
|
||||
product = product_obj.browse(vals['product'])
|
||||
res['uom'] = product.default_uom.id
|
||||
res['uom.rec_name'] = product.default_uom.rec_name
|
||||
res['unit_digits'] = product.default_uom.digits
|
||||
return res
|
||||
|
||||
def get_uom(self, cursor, user, ids, name, context=None):
|
||||
def get_uom(self, ids, name):
|
||||
res = {}
|
||||
for line in self.browse(cursor, user, ids, context=context):
|
||||
for line in self.browse(ids):
|
||||
res[line.id] = line.product.default_uom.id
|
||||
return res
|
||||
|
||||
def get_unit_digits(self, cursor, user, ids, name, context=None):
|
||||
def get_unit_digits(self, ids, name):
|
||||
res = {}
|
||||
for line in self.browse(cursor, user, ids, context=context):
|
||||
for line in self.browse(ids):
|
||||
res[line.id] = line.product.default_uom.digits
|
||||
return res
|
||||
|
||||
def cancel_move(self, cursor, user, lines, context=None):
|
||||
def cancel_move(self, lines):
|
||||
move_obj = self.pool.get('stock.move')
|
||||
move_obj.write(
|
||||
cursor, user, [l.move.id for l in lines if l.move], {'state': 'cancel'},
|
||||
context=context)
|
||||
move_obj.delete(
|
||||
cursor, user, [l.move.id for l in lines if l.move], context=context)
|
||||
self.write(
|
||||
cursor, user, [l.id for l in lines if l.move], {'move': False},
|
||||
context=context)
|
||||
move_obj.write( [l.move.id for l in lines if l.move], {
|
||||
'state': 'cancel',
|
||||
})
|
||||
move_obj.delete([l.move.id for l in lines if l.move])
|
||||
self.write([l.id for l in lines if l.move], {
|
||||
'move': False,
|
||||
})
|
||||
|
||||
def create_move(self, cursor, user, line, context=None):
|
||||
def create_move(self, line):
|
||||
'''
|
||||
Create move for an inventory line
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param line: a BrowseRecord of inventory.line
|
||||
:param context: the context
|
||||
:return: the stock.move id or None
|
||||
'''
|
||||
move_obj = self.pool.get('stock.move')
|
||||
@@ -290,7 +272,7 @@ class InventoryLine(ModelSQL, ModelView):
|
||||
(from_location, to_location, delta_qty) = \
|
||||
(to_location, from_location, -delta_qty)
|
||||
|
||||
move_id = move_obj.create(cursor, user, {
|
||||
move_id = move_obj.create({
|
||||
'from_location': from_location,
|
||||
'to_location': to_location,
|
||||
'quantity': delta_qty,
|
||||
@@ -299,21 +281,19 @@ class InventoryLine(ModelSQL, ModelView):
|
||||
'company': line.inventory.company.id,
|
||||
'state': 'done',
|
||||
'effective_date': line.inventory.date,
|
||||
}, context=context)
|
||||
self.write(cursor, user, line.id, {'move': move_id}, context=context)
|
||||
})
|
||||
self.write(line.id, {
|
||||
'move': move_id,
|
||||
})
|
||||
return move_id
|
||||
|
||||
def update_values4complete(self, cursor, user, line, quantity, uom_id,
|
||||
context=None):
|
||||
def update_values4complete(self, line, quantity, uom_id):
|
||||
'''
|
||||
Return update values to complete inventory
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param line: a BrowseRecord of inventory.line
|
||||
:param quantity: the actual product quantity for the inventory location
|
||||
:param uom_id: the UoM id of the product line
|
||||
:param context: the context
|
||||
:return: a dictionary
|
||||
'''
|
||||
res = {}
|
||||
@@ -328,18 +308,14 @@ class InventoryLine(ModelSQL, ModelView):
|
||||
res['quantity'] = max(quantity, 0.0)
|
||||
return res
|
||||
|
||||
def create_values4complete(self, cursor, user, product_id, inventory,
|
||||
quantity, uom_id, context=None):
|
||||
def create_values4complete(self, product_id, inventory, quantity, uom_id):
|
||||
'''
|
||||
Return create values to complete inventory
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param product_id: the product.product id
|
||||
:param inventory: a BrowseRecord of inventory.inventory
|
||||
:param quantity: the actual product quantity for the inventory location
|
||||
:param uom_id: the UoM id of the product_id
|
||||
:param context: the context
|
||||
:return: a dictionary
|
||||
'''
|
||||
return {
|
||||
@@ -366,9 +342,9 @@ class CompleteInventory(Wizard):
|
||||
},
|
||||
}
|
||||
|
||||
def _complete(self, cursor, user, data, context=None):
|
||||
def _complete(self, data):
|
||||
inventory_obj = self.pool.get('stock.inventory')
|
||||
inventory_obj.complete_lines(cursor, user, data['ids'], context=context)
|
||||
inventory_obj.complete_lines(data['ids'])
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
+106
-121
@@ -1,11 +1,12 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
"Wharehouse"
|
||||
from __future__ import with_statement
|
||||
import datetime
|
||||
from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.wizard import Wizard
|
||||
from trytond.backend import TableHandler
|
||||
from trytond.pyson import Not, Bool, Eval, Equal, PYSONEncoder, Date
|
||||
import datetime
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
STATES = {
|
||||
'readonly': Not(Bool(Eval('active'))),
|
||||
@@ -90,110 +91,101 @@ class Location(ModelSQL, ModelView):
|
||||
'child_of_warehouse': 'Location "%s" must be a child of warehouse "%s"!',
|
||||
})
|
||||
|
||||
def init(self, cursor, module_name):
|
||||
super(Location, self).init(cursor, module_name)
|
||||
def init(self, module_name):
|
||||
super(Location, self).init(module_name)
|
||||
cursor = Transaction().cursor
|
||||
|
||||
table = TableHandler(cursor, self, module_name)
|
||||
table.index_action(['left', 'right'], 'add')
|
||||
|
||||
def check_type_for_moves(self, cursor, user, ids):
|
||||
def check_type_for_moves(self, ids):
|
||||
""" Check locations with moves have types compatible with moves. """
|
||||
invalid_move_types = ['warehouse', 'view']
|
||||
move_obj = self.pool.get('stock.move')
|
||||
for location in self.browse(cursor, user, ids):
|
||||
for location in self.browse(ids):
|
||||
if location.type in invalid_move_types and \
|
||||
move_obj.search(cursor, user, ['OR',
|
||||
move_obj.search(['OR',
|
||||
('to_location', '=', location.id),
|
||||
('from_location', '=', location.id)]):
|
||||
('from_location', '=', location.id),
|
||||
]):
|
||||
return False
|
||||
return True
|
||||
|
||||
def default_active(self, cursor, user, context=None):
|
||||
def default_active(self):
|
||||
return True
|
||||
|
||||
def default_left(self, cursor, user, context=None):
|
||||
def default_left(self):
|
||||
return 0
|
||||
|
||||
def default_right(self, cursor, user, context=None):
|
||||
def default_right(self):
|
||||
return 0
|
||||
|
||||
def default_type(self, cursor, user, context=None):
|
||||
def default_type(self):
|
||||
return 'storage'
|
||||
|
||||
def check_xml_record(self, cursor, user, ids, values, context=None):
|
||||
def check_xml_record(self, ids, values):
|
||||
return True
|
||||
|
||||
def search_rec_name(self, cursor, user, name, clause, context=None):
|
||||
ids = self.search(cursor, user, [('code', '=', clause[2])],
|
||||
order=[], context=context)
|
||||
def search_rec_name(self, name, clause):
|
||||
ids = self.search([
|
||||
('code', '=', clause[2]),
|
||||
], order=[])
|
||||
if ids:
|
||||
return [('id', 'in', ids)]
|
||||
return [(self._rec_name,) + clause[1:]]
|
||||
|
||||
def get_quantity(self, cursor, user, ids, name, context=None):
|
||||
def get_quantity(self, ids, name):
|
||||
product_obj = self.pool.get('product.product')
|
||||
date_obj = self.pool.get('ir.date')
|
||||
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
if (not context.get('product')) \
|
||||
or not (isinstance(context['product'], (int, long))):
|
||||
if (not Transaction().context.get('product')) \
|
||||
or not (isinstance(Transaction().context['product'],
|
||||
(int, long))):
|
||||
return dict([(i, 0) for i in ids])
|
||||
|
||||
ctx = context.copy()
|
||||
ctx['active_test'] = False
|
||||
if not product_obj.search(cursor, user, [
|
||||
('id', '=', context['product']),
|
||||
], context=ctx):
|
||||
return dict([(i, 0) for i in ids])
|
||||
with Transaction().set_context(active_test=False):
|
||||
if not product_obj.search([
|
||||
('id', '=', Transaction().context['product']),
|
||||
]):
|
||||
return dict([(i, 0) for i in ids])
|
||||
|
||||
if name == 'quantity' and \
|
||||
context.get('stock_date_end') > \
|
||||
date_obj.today(cursor, user, context=context):
|
||||
|
||||
context = context.copy()
|
||||
context['stock_date_end'] = date_obj.today(
|
||||
cursor, user, context=context)
|
||||
context = {}
|
||||
if (name == 'quantity'
|
||||
and Transaction().context.get('stock_date_end') >
|
||||
date_obj.today()):
|
||||
context['stock_date_end'] = date_obj.today()
|
||||
|
||||
if name == 'forecast_quantity':
|
||||
context = context.copy()
|
||||
context['forecast'] = True
|
||||
if not context.get('stock_date_end'):
|
||||
if not Transaction().context.get('stock_date_end'):
|
||||
context['stock_date_end'] = datetime.date.max
|
||||
|
||||
pbl = product_obj.products_by_location(cursor, user, location_ids=ids,
|
||||
product_ids=[context['product']], with_childs=True, skip_zero=False,
|
||||
context=context).iteritems()
|
||||
with Transaction().set_context(context):
|
||||
pbl = product_obj.products_by_location(location_ids=ids,
|
||||
product_ids=[Transaction().context['product']],
|
||||
with_childs=True, skip_zero=False).iteritems()
|
||||
|
||||
return dict([(loc,qty) for (loc,prod), qty in pbl])
|
||||
|
||||
def view_header_get(self, cursor, user, value, view_type='form',
|
||||
context=None):
|
||||
def view_header_get(self, value, view_type='form'):
|
||||
product_obj = self.pool.get('product.product')
|
||||
if context is None:
|
||||
context = {}
|
||||
ctx = context.copy()
|
||||
ctx['active_test'] = False
|
||||
if context.get('product') \
|
||||
and isinstance(context['product'], (int, long)) \
|
||||
and product_obj.search(cursor, user, [
|
||||
('id', '=', context['product']),
|
||||
], context=ctx):
|
||||
product = product_obj.browse(cursor, user, context['product'],
|
||||
context=context)
|
||||
return value + ': ' + product.rec_name + \
|
||||
' (' + product.default_uom.rec_name + ')'
|
||||
if (Transaction().context.get('product')
|
||||
and isinstance(Transaction().context['product'], (int, long))):
|
||||
with Transaction().set_context(active_test=False):
|
||||
product_ids = product_obj.search([
|
||||
('id', '=', Transaction().context['product']),
|
||||
], limit=1)
|
||||
if product_ids:
|
||||
product = product_obj.browse(product_ids[0])
|
||||
return value + ': ' + product.rec_name + \
|
||||
' (' + product.default_uom.rec_name + ')'
|
||||
return value
|
||||
|
||||
def _set_warehouse_parent(self, cursor, user, locations, context=None):
|
||||
def _set_warehouse_parent(self, locations):
|
||||
'''
|
||||
Set the parent of child location of warehouse if not set
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param locations: a BrowseRecordList of locations
|
||||
:param context: the context
|
||||
:return: a list with updated location ids
|
||||
'''
|
||||
location_ids = set()
|
||||
@@ -207,35 +199,32 @@ class Location(ModelSQL, ModelView):
|
||||
location_ids.add(location.storage_location.id)
|
||||
location_ids = list(location_ids)
|
||||
if location_ids:
|
||||
self.write(cursor, user, location_ids, {
|
||||
self.write(location_ids, {
|
||||
'parent': location.id,
|
||||
}, context=context)
|
||||
})
|
||||
|
||||
def create(self, cursor, user, vals, context=None):
|
||||
res = super(Location, self).create(cursor, user, vals, context=context)
|
||||
locations = self.browse(cursor, user, [res], context=context)
|
||||
self._set_warehouse_parent(cursor, user, locations, context=context)
|
||||
def create(self, vals):
|
||||
res = super(Location, self).create(vals)
|
||||
locations = self.browse([res])
|
||||
self._set_warehouse_parent(locations)
|
||||
return res
|
||||
|
||||
def write(self, cursor, user, ids, vals, context=None):
|
||||
res = super(Location, self).write(cursor, user, ids, vals,
|
||||
context=context)
|
||||
def write(self, ids, vals):
|
||||
res = super(Location, self).write(ids, vals)
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
locations = self.browse(cursor, user, ids, context=context)
|
||||
self._set_warehouse_parent(cursor, user, locations, context=context)
|
||||
locations = self.browse(ids)
|
||||
self._set_warehouse_parent(locations)
|
||||
|
||||
check_wh = self.search(
|
||||
cursor, user,
|
||||
[('type', '=', 'warehouse'),
|
||||
['OR',
|
||||
('storage_location', 'in', ids),
|
||||
('input_location', 'in', ids),
|
||||
('output_location', 'in', ids)
|
||||
]],
|
||||
context=context)
|
||||
check_wh = self.search([
|
||||
('type', '=', 'warehouse'),
|
||||
['OR',
|
||||
('storage_location', 'in', ids),
|
||||
('input_location', 'in', ids),
|
||||
('output_location', 'in', ids),
|
||||
]])
|
||||
|
||||
warehouses = self.browse(cursor, user, check_wh, context=context)
|
||||
warehouses = self.browse(check_wh)
|
||||
fields = ('storage_location', 'input_location', 'output_location')
|
||||
wh2childs = {}
|
||||
for warehouse in warehouses:
|
||||
@@ -243,19 +232,16 @@ class Location(ModelSQL, ModelView):
|
||||
for location in locations:
|
||||
if location.id not in in_out_sto:
|
||||
continue
|
||||
childs = wh2childs.setdefault(
|
||||
warehouse.id,
|
||||
self.search(
|
||||
cursor, user, [('parent', 'child_of', warehouse.id)],
|
||||
context=context))
|
||||
childs = wh2childs.setdefault(warehouse.id, self.search([
|
||||
('parent', 'child_of', warehouse.id),
|
||||
]))
|
||||
if location.id not in childs:
|
||||
self.raise_user_error(
|
||||
cursor, 'child_of_warehouse',
|
||||
(location.name, warehouse.name), context=context)
|
||||
self.raise_user_error('child_of_warehouse',
|
||||
(location.name, warehouse.name))
|
||||
|
||||
return res
|
||||
|
||||
def copy(self, cursor, user, ids, default=None, context=None):
|
||||
def copy(self, ids, default=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
int_id = False
|
||||
@@ -267,7 +253,7 @@ class Location(ModelSQL, ModelView):
|
||||
default['right'] = 0
|
||||
|
||||
res = []
|
||||
locations = self.browse(cursor, user, ids, context=context)
|
||||
locations = self.browse(ids)
|
||||
for location in locations:
|
||||
if location.type == 'warehouse':
|
||||
|
||||
@@ -278,32 +264,31 @@ class Location(ModelSQL, ModelView):
|
||||
wh_default['storage_location'] = False
|
||||
wh_default['childs'] = False
|
||||
|
||||
new_id = super(Location, self).copy(
|
||||
cursor, user, location.id, default=wh_default,
|
||||
context=context)
|
||||
new_id = super(Location, self).copy(location.id,
|
||||
default=wh_default)
|
||||
|
||||
child_context = context and context.copy() or {}
|
||||
child_context['cp_warehouse_locations'] = {
|
||||
'input_location': location.input_location.id,
|
||||
'output_location': location.output_location.id,
|
||||
'storage_location': location.storage_location.id}
|
||||
child_context['cp_warehouse_id'] = new_id
|
||||
|
||||
self.copy(
|
||||
cursor, user, [c.id for c in location.childs],
|
||||
default={'parent':new_id}, context=child_context)
|
||||
self.write(
|
||||
cursor, user, new_id, {'type': 'warehouse'}, context=context)
|
||||
with Transaction().set_context(
|
||||
cp_warehouse_locations={
|
||||
'input_location': location.input_location.id,
|
||||
'output_location': location.output_location.id,
|
||||
'storage_location': location.storage_location.id,
|
||||
},
|
||||
cp_warehouse_id=new_id):
|
||||
self.copy([c.id for c in location.childs],
|
||||
default={'parent': new_id})
|
||||
self.write(new_id, {
|
||||
'type': 'warehouse',
|
||||
})
|
||||
else:
|
||||
new_id = super(Location, self).copy(
|
||||
cursor, user, location.id, default=default, context=context)
|
||||
warehouse_locations = context.get('cp_warehouse_locations', {})
|
||||
new_id = super(Location, self).copy(location.id,
|
||||
default=default)
|
||||
warehouse_locations = Transaction().context.get(
|
||||
'cp_warehouse_locations') or {}
|
||||
if location.id in warehouse_locations.values():
|
||||
for field, loc_id in warehouse_locations.iteritems():
|
||||
if loc_id == location.id:
|
||||
self.write(
|
||||
cursor, user, context['cp_warehouse_id'],
|
||||
{field: new_id}, context=context)
|
||||
self.write(Transaction().context['cp_warehouse_id'],
|
||||
{field: new_id})
|
||||
|
||||
res.append(new_id)
|
||||
|
||||
@@ -335,9 +320,9 @@ class ChooseStockDateInit(ModelView):
|
||||
'* An empty value is an infinite date in the future.\n'\
|
||||
'* A date in the past will provide historical values.')
|
||||
|
||||
def default_forecast_date(self, cursor, user, context=None):
|
||||
def default_forecast_date(self):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
return date_obj.today(cursor, user, context=context)
|
||||
return date_obj.today()
|
||||
|
||||
ChooseStockDateInit()
|
||||
|
||||
@@ -365,21 +350,21 @@ class OpenProduct(Wizard):
|
||||
},
|
||||
}
|
||||
|
||||
def _action_open_product(self, cursor, user, data, context=None):
|
||||
def _action_open_product(self, data):
|
||||
model_data_obj = self.pool.get('ir.model.data')
|
||||
act_window_obj = self.pool.get('ir.action.act_window')
|
||||
act_window_id = model_data_obj.get_id(cursor, user, 'stock',
|
||||
'act_product_by_location', context=context)
|
||||
res = act_window_obj.read(cursor, user, act_window_id, context=context)
|
||||
act_window_id = model_data_obj.get_id('stock',
|
||||
'act_product_by_location')
|
||||
res = act_window_obj.read(act_window_id)
|
||||
|
||||
ctx = {}
|
||||
ctx['locations'] = data['ids']
|
||||
context = {}
|
||||
context['locations'] = data['ids']
|
||||
if data['form']['forecast_date']:
|
||||
date = data['form']['forecast_date']
|
||||
else:
|
||||
date = datetime.date.max
|
||||
ctx['stock_date_end'] = Date(date.year, date.month, date.day)
|
||||
res['pyson_context'] = PYSONEncoder().encode(ctx)
|
||||
context['stock_date_end'] = Date(date.year, date.month, date.day)
|
||||
res['pyson_context'] = PYSONEncoder().encode(context)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
"Move"
|
||||
from __future__ import with_statement
|
||||
from decimal import Decimal
|
||||
from trytond.model import ModelView, ModelSQL, fields, OPERATORS
|
||||
from trytond.backend import TableHandler
|
||||
from trytond.pyson import In, Eval, Not, In, Equal, If, Get, Bool
|
||||
from decimal import Decimal
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
STATES = {
|
||||
'readonly': In(Eval('state'), ['cancel', 'done']),
|
||||
@@ -117,7 +118,8 @@ class Move(ModelSQL, ModelView):
|
||||
'service_product': 'You can not use service products for a move!',
|
||||
})
|
||||
|
||||
def init(self, cursor, module_name):
|
||||
def init(self, module_name):
|
||||
cursor = Transaction().cursor
|
||||
# Migration from 1.2: packing renamed into shipment
|
||||
table = TableHandler(cursor, self, module_name)
|
||||
table.drop_constraint('check_packing')
|
||||
@@ -128,7 +130,7 @@ class Move(ModelSQL, ModelView):
|
||||
table.index_action(old_column, action='remove')
|
||||
table.drop_fk(old_column)
|
||||
table.column_rename(old_column, new_column)
|
||||
super(Move, self).init(cursor, module_name)
|
||||
super(Move, self).init(module_name)
|
||||
|
||||
# Migration from 1.0 check_packing_in_out has been removed
|
||||
table = TableHandler(cursor, self, module_name)
|
||||
@@ -137,225 +139,179 @@ class Move(ModelSQL, ModelView):
|
||||
# Add index on create_date
|
||||
table.index_action('create_date', action='add')
|
||||
|
||||
def default_planned_date(self, cursor, user, context=None):
|
||||
if context and context.get('planned_date'):
|
||||
return context.get('planned_date')
|
||||
def default_planned_date(self):
|
||||
return Transaction().context.get('planned_date') or False
|
||||
|
||||
def default_to_location(self, cursor, user, context=None):
|
||||
def default_to_location(self):
|
||||
location_obj = self.pool.get('stock.location')
|
||||
party_obj = self.pool.get('party.party')
|
||||
res = False
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
warehouse = None
|
||||
if context.get('warehouse'):
|
||||
warehouse = location_obj.browse(cursor, user, context['warehouse'],
|
||||
context=context)
|
||||
if Transaction().context.get('warehouse'):
|
||||
warehouse = location_obj.browse(Transaction().context['warehouse'])
|
||||
|
||||
if context.get('type', '') == 'inventory_in':
|
||||
if Transaction().context.get('type', '') == 'inventory_in':
|
||||
if warehouse:
|
||||
res = warehouse.storage_location.id
|
||||
elif context.get('type', '') == 'inventory_out':
|
||||
elif Transaction().context.get('type', '') == 'inventory_out':
|
||||
if warehouse:
|
||||
res = warehouse.output_location.id
|
||||
elif context.get('type', '') == 'incoming':
|
||||
elif Transaction().context.get('type', '') == 'incoming':
|
||||
if warehouse:
|
||||
res = warehouse.input_location.id
|
||||
elif context.get('type', '') == 'outgoing':
|
||||
if context.get('customer'):
|
||||
customer = party_obj.browse(cursor, user, context['customer'],
|
||||
context=context)
|
||||
elif Transaction().context.get('type', '') == 'outgoing':
|
||||
if Transaction().context.get('customer'):
|
||||
customer = party_obj.browse(Transaction().context['customer'])
|
||||
res = customer.customer_location.id
|
||||
|
||||
if context.get('to_location'):
|
||||
res = context.get('to_location')
|
||||
if Transaction().context.get('to_location'):
|
||||
res = Transaction().context['to_location']
|
||||
return res
|
||||
|
||||
def default_from_location(self, cursor, user, context=None):
|
||||
def default_from_location(self):
|
||||
location_obj = self.pool.get('stock.location')
|
||||
party_obj = self.pool.get('party.party')
|
||||
res = False
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
warehouse = None
|
||||
if context.get('warehouse'):
|
||||
warehouse = location_obj.browse(cursor, user, context['warehouse'],
|
||||
context=context)
|
||||
if Transaction().context.get('warehouse'):
|
||||
warehouse = location_obj.browse(Transaction().context['warehouse'])
|
||||
|
||||
if context.get('type', '') == 'inventory_in':
|
||||
if Transaction().context.get('type', '') == 'inventory_in':
|
||||
if warehouse:
|
||||
res = warehouse.input_location.id
|
||||
elif context.get('type', '') == 'inventory_out':
|
||||
elif Transaction().context.get('type', '') == 'inventory_out':
|
||||
if warehouse:
|
||||
res = warehouse.storage_location.id
|
||||
elif context.get('type', '') == 'outgoing':
|
||||
elif Transaction().context.get('type', '') == 'outgoing':
|
||||
if warehouse:
|
||||
res = warehouse.output_location.id
|
||||
elif context.get('type', '') == 'incoming':
|
||||
if context.get('supplier'):
|
||||
supplier = party_obj.browse(cursor, user, context['supplier'],
|
||||
context=context)
|
||||
elif Transaction().context.get('type', '') == 'incoming':
|
||||
if Transaction().context.get('supplier'):
|
||||
supplier = party_obj.browse(Transaction().context['supplier'])
|
||||
res = supplier.supplier_location.id
|
||||
elif context.get('customer'):
|
||||
customer = party_obj.browse(cursor, user, context['customer'],
|
||||
context=context)
|
||||
elif Transaction().context.get('customer'):
|
||||
customer = party_obj.browse(Transaction().context['customer'])
|
||||
res = customer.customer_location.id
|
||||
|
||||
if context.get('from_location'):
|
||||
res = context.get('from_location')
|
||||
if Transaction().context.get('from_location'):
|
||||
res = Transaction().context['from_location']
|
||||
return res
|
||||
|
||||
def default_state(self, cursor, user, context=None):
|
||||
def default_state(self):
|
||||
return 'draft'
|
||||
|
||||
def default_company(self, cursor, user, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if context.get('company'):
|
||||
return context['company']
|
||||
return False
|
||||
def default_company(self):
|
||||
return Transaction().context.get('company') or False
|
||||
|
||||
def default_currency(self, cursor, user, context=None):
|
||||
def default_currency(self):
|
||||
company_obj = self.pool.get('company.company')
|
||||
currency_obj = self.pool.get('currency.currency')
|
||||
if context is None:
|
||||
context = {}
|
||||
company = None
|
||||
if context.get('company'):
|
||||
company = company_obj.browse(cursor, user, context['company'],
|
||||
context=context)
|
||||
company = Transaction().context.get('company')
|
||||
if company:
|
||||
company = company_obj.browse(company)
|
||||
return company.currency.id
|
||||
return False
|
||||
|
||||
def on_change_with_unit_digits(self, cursor, user, vals, context=None):
|
||||
def on_change_with_unit_digits(self, vals):
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
if vals.get('uom'):
|
||||
uom = uom_obj.browse(cursor, user, vals['uom'],
|
||||
context=context)
|
||||
uom = uom_obj.browse(vals['uom'])
|
||||
return uom.digits
|
||||
return 2
|
||||
|
||||
def get_unit_digits(self, cursor, user, ids, name, context=None):
|
||||
def get_unit_digits(self, ids, name):
|
||||
res = {}
|
||||
for move in self.browse(cursor, user, ids, context=context):
|
||||
for move in self.browse(ids):
|
||||
res[move.id] = move.uom.digits
|
||||
return res
|
||||
|
||||
def on_change_product(self, cursor, user, vals, context=None):
|
||||
def on_change_product(self, vals):
|
||||
product_obj = self.pool.get('product.product')
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
currency_obj = self.pool.get('currency.currency')
|
||||
company_obj = self.pool.get('company.company')
|
||||
location_obj = self.pool.get('stock.location')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
res = {
|
||||
'unit_price': Decimal('0.0'),
|
||||
}
|
||||
if vals.get('product'):
|
||||
product = product_obj.browse(cursor, user, vals['product'],
|
||||
context=context)
|
||||
product = product_obj.browse(vals['product'])
|
||||
res['uom'] = product.default_uom.id
|
||||
res['uom.rec_name'] = product.default_uom.rec_name
|
||||
res['unit_digits'] = product.default_uom.digits
|
||||
to_location = None
|
||||
if vals.get('to_location'):
|
||||
to_location = location_obj.browse(cursor, user,
|
||||
vals['to_location'], context=context)
|
||||
to_location = location_obj.browse(vals['to_location'])
|
||||
if to_location and to_location.type == 'storage':
|
||||
unit_price = product.cost_price
|
||||
if vals.get('uom') and vals['uom'] != product.default_uom.id:
|
||||
uom = uom_obj.browse(cursor, user, vals['uom'],
|
||||
context=context)
|
||||
unit_price = uom_obj.compute_price(cursor, user,
|
||||
product.default_uom, unit_price, uom,
|
||||
context=context)
|
||||
uom = uom_obj.browse(vals['uom'])
|
||||
unit_price = uom_obj.compute_price(product.default_uom,
|
||||
unit_price, uom)
|
||||
if vals.get('currency') and vals.get('company'):
|
||||
currency = currency_obj.browse(cursor, user,
|
||||
vals['currency'], context=context)
|
||||
company = company_obj.browse(cursor, user,
|
||||
vals['company'], context=context)
|
||||
unit_price = currency_obj.compute(cursor, user,
|
||||
company.currency, unit_price, currency,
|
||||
round=False, context=context)
|
||||
currency = currency_obj.browse(vals['currency'])
|
||||
company = company_obj.browse(vals['company'])
|
||||
unit_price = currency_obj.compute(company.currency,
|
||||
unit_price, currency, round=False)
|
||||
res['unit_price'] = unit_price
|
||||
return res
|
||||
|
||||
def on_change_uom(self, cursor, user, vals, context=None):
|
||||
def on_change_uom(self, vals):
|
||||
product_obj = self.pool.get('product.product')
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
currency_obj = self.pool.get('currency.currency')
|
||||
company_obj = self.pool.get('company.company')
|
||||
location_obj = self.pool.get('stock.location')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
res = {
|
||||
'unit_price': Decimal('0.0'),
|
||||
}
|
||||
if vals.get('product'):
|
||||
product = product_obj.browse(cursor, user, vals['product'],
|
||||
context=context)
|
||||
product = product_obj.browse(vals['product'])
|
||||
to_location = None
|
||||
if vals.get('to_location'):
|
||||
to_location = location_obj.browse(cursor, user,
|
||||
vals['to_location'], context=context)
|
||||
to_location = location_obj.browse(vals['to_location'])
|
||||
if to_location and to_location.type == 'storage':
|
||||
unit_price = product.cost_price
|
||||
if vals.get('uom') and vals['uom'] != product.default_uom.id:
|
||||
uom = uom_obj.browse(cursor, user, vals['uom'],
|
||||
context=context)
|
||||
unit_price = uom_obj.compute_price(cursor, user,
|
||||
product.default_uom, unit_price, uom,
|
||||
context=context)
|
||||
uom = uom_obj.browse(vals['uom'])
|
||||
unit_price = uom_obj.compute_price(product.default_uom,
|
||||
unit_price, uom)
|
||||
if vals.get('currency') and vals.get('company'):
|
||||
currency = currency_obj.browse(cursor, user,
|
||||
vals['currency'], context=context)
|
||||
company = company_obj.browse(cursor, user,
|
||||
vals['company'], context=context)
|
||||
unit_price = currency_obj.compute(cursor, user,
|
||||
company.currency, unit_price, currency,
|
||||
round=False, context=context)
|
||||
currency = currency_obj.browse(vals['currency'])
|
||||
company = company_obj.browse(vals['company'])
|
||||
unit_price = currency_obj.compute(company.currency,
|
||||
unit_price, currency, round=False)
|
||||
res['unit_price'] = unit_price
|
||||
return res
|
||||
|
||||
def default_unit_price_required(self, cursor, user, context=None):
|
||||
from_location = self.default_from_location(cursor, user,
|
||||
context=context)
|
||||
to_location = self.default_to_location(cursor,user,
|
||||
context=context)
|
||||
def default_unit_price_required(self):
|
||||
from_location = self.default_from_location()
|
||||
to_location = self.default_to_location()
|
||||
vals = {
|
||||
'from_location': from_location,
|
||||
'to_location': to_location,
|
||||
}
|
||||
return self.on_change_with_unit_price_required(cursor, user,
|
||||
vals, context=context)
|
||||
return self.on_change_with_unit_price_required(vals)
|
||||
|
||||
def on_change_with_unit_price_required(self, cursor, user, vals,
|
||||
context=None):
|
||||
def on_change_with_unit_price_required(self, vals):
|
||||
location_obj = self.pool.get('stock.location')
|
||||
if vals.get('from_location'):
|
||||
from_location = location_obj.browse(cursor, user,
|
||||
vals['from_location'], context=context)
|
||||
from_location = location_obj.browse(vals['from_location'])
|
||||
if from_location.type == 'supplier':
|
||||
return True
|
||||
if vals.get('to_location'):
|
||||
to_location = location_obj.browse(cursor, user,
|
||||
vals['to_location'], context=context)
|
||||
to_location = location_obj.browse(vals['to_location'])
|
||||
if to_location.type == 'customer':
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_unit_price_required(self, cursor, user, ids, name, context=None):
|
||||
def get_unit_price_required(self, ids, name):
|
||||
res = {}
|
||||
for move in self.browse(cursor, user, ids, context=context):
|
||||
for move in self.browse(ids):
|
||||
res[move.id] = False
|
||||
if move.from_location.type == 'supplier':
|
||||
res[move.id] = True
|
||||
@@ -363,26 +319,26 @@ class Move(ModelSQL, ModelView):
|
||||
res[move.id] = True
|
||||
return res
|
||||
|
||||
def check_product_type(self, cursor, user, ids):
|
||||
for move in self.browse(cursor, user, ids):
|
||||
def check_product_type(self, ids):
|
||||
for move in self.browse(ids):
|
||||
if move.product.type == 'service':
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_rec_name(self, cursor, user, ids, name, context=None):
|
||||
def get_rec_name(self, ids, name):
|
||||
if not ids:
|
||||
return {}
|
||||
res = {}
|
||||
moves = self.browse(cursor, user, ids, context=context)
|
||||
moves = self.browse(ids)
|
||||
for m in moves:
|
||||
res[m.id] = "%s%s %s" % (m.quantity, m.uom.symbol, m.product.rec_name)
|
||||
return res
|
||||
|
||||
def search_rec_name(self, cursor, user, name, clause, context=None):
|
||||
def search_rec_name(self, name, clause):
|
||||
return [('product',) + clause[1:]]
|
||||
|
||||
def search(self, cursor, user, args, offset=0, limit=None, order=None,
|
||||
context=None, count=False, query_string=False):
|
||||
def search(self, args, offset=0, limit=None, order=None, count=False,
|
||||
query_string=False):
|
||||
location_obj = self.pool.get('stock.location')
|
||||
|
||||
args = args[:]
|
||||
@@ -396,8 +352,7 @@ class Move(ModelSQL, ModelView):
|
||||
args[i][0] == 'to_location_warehouse':
|
||||
location_id = False
|
||||
if args[i][2]:
|
||||
location = location_obj.browse(cursor, user,
|
||||
args[i][2], context=context)
|
||||
location = location_obj.browse(args[i][2])
|
||||
if location.type == 'warehouse':
|
||||
location_id = location.input_location.id
|
||||
args[i] = ('to_location', args[i][1], location_id)
|
||||
@@ -405,17 +360,14 @@ class Move(ModelSQL, ModelView):
|
||||
process_args(args[i])
|
||||
i += 1
|
||||
process_args(args)
|
||||
return super(Move, self).search(cursor, user, args, offset=offset,
|
||||
limit=limit, order=order, context=context, count=count,
|
||||
query_string=query_string)
|
||||
return super(Move, self).search(args, offset=offset, limit=limit,
|
||||
order=order, count=count, query_string=query_string)
|
||||
|
||||
def _update_product_cost_price(self, cursor, user, product_id, quantity, uom,
|
||||
unit_price, currency, company, context=None):
|
||||
def _update_product_cost_price(self, product_id, quantity, uom, unit_price,
|
||||
currency, company):
|
||||
"""
|
||||
Update the cost price on the given product
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param product_id: the id of the product
|
||||
:param quantity: the quantity of the product, positive if incoming and
|
||||
negative if outgoing
|
||||
@@ -423,7 +375,6 @@ class Move(ModelSQL, ModelView):
|
||||
:param unit_price: the unit price of the product
|
||||
:param currency: the currency of the unit price
|
||||
:param company: the company id ot a BrowseRecord of the company
|
||||
:param context: the context
|
||||
"""
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
product_obj = self.pool.get('product.product')
|
||||
@@ -433,31 +384,28 @@ class Move(ModelSQL, ModelView):
|
||||
company_obj = self.pool.get('company.company')
|
||||
date_obj = self.pool.get('ir.date')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
if isinstance(uom, (int, long)):
|
||||
uom = uom_obj.browse(cursor, user, uom, context=context)
|
||||
uom = uom_obj.browse(uom)
|
||||
if isinstance(company, (int, long)):
|
||||
company = company_obj.browse(cursor, user, company, context=context)
|
||||
company = company_obj.browse(company)
|
||||
|
||||
ctx = context and context.copy() or {}
|
||||
ctx['locations'] = location_obj.search(
|
||||
cursor, user, [('type', '=', 'storage')], context=context)
|
||||
ctx['stock_date_end'] = date_obj.today(cursor, user, context=context)
|
||||
product = product_obj.browse(cursor, user, product_id, context=ctx)
|
||||
qty = uom_obj.compute_qty(
|
||||
cursor, user, uom, quantity, product.default_uom, context=context)
|
||||
context = {}
|
||||
context['locations'] = location_obj.search([
|
||||
('type', '=', 'storage'),
|
||||
])
|
||||
context['stock_date_end'] = date_obj.today()
|
||||
with Transaction().set_context(context):
|
||||
product = product_obj.browse(product_id)
|
||||
qty = uom_obj.compute_qty(uom, quantity, product.default_uom)
|
||||
|
||||
qty = Decimal(str(qty))
|
||||
product_qty = Decimal(str(product.template.quantity))
|
||||
# convert wrt currency
|
||||
unit_price = currency_obj.compute(
|
||||
cursor, user, currency, unit_price, company.currency,
|
||||
round=False, context=context)
|
||||
unit_price = currency_obj.compute(currency, unit_price,
|
||||
company.currency, round=False)
|
||||
# convert wrt to the uom
|
||||
unit_price = uom_obj.compute_price(
|
||||
cursor, user, uom, unit_price, product.default_uom, context=context)
|
||||
unit_price = uom_obj.compute_price(uom, unit_price,
|
||||
product.default_uom)
|
||||
if product_qty + qty != Decimal('0.0'):
|
||||
new_cost_price = (
|
||||
(product.cost_price * product_qty) + (unit_price * qty)
|
||||
@@ -472,13 +420,12 @@ class Move(ModelSQL, ModelView):
|
||||
new_cost_price = new_cost_price.quantize(
|
||||
Decimal(str(10.0**-digits[1])))
|
||||
|
||||
ctx = context.copy()
|
||||
ctx['user'] = user
|
||||
product_obj.write(
|
||||
cursor, 0, product.id, {'cost_price': new_cost_price},
|
||||
context=ctx)
|
||||
with Transaction().set_user(0, set_context=True):
|
||||
product_obj.write(product.id, {
|
||||
'cost_price': new_cost_price,
|
||||
})
|
||||
|
||||
def create(self, cursor, user, vals, context=None):
|
||||
def create(self, vals):
|
||||
location_obj = self.pool.get('stock.location')
|
||||
product_obj = self.pool.get('product.product')
|
||||
date_obj = self.pool.get('ir.date')
|
||||
@@ -487,125 +434,101 @@ class Move(ModelSQL, ModelView):
|
||||
|
||||
if vals.get('state') == 'done':
|
||||
if not vals.get('effective_date'):
|
||||
vals['effective_date'] = date_obj.today(cursor, user,
|
||||
context=context)
|
||||
from_location = location_obj.browse(cursor, user,
|
||||
vals['from_location'], context=context)
|
||||
to_location = location_obj.browse(cursor, user,
|
||||
vals['to_location'], context=context)
|
||||
product = product_obj.browse(cursor, user, vals['product'],
|
||||
context=context)
|
||||
vals['effective_date'] = date_obj.today()
|
||||
from_location = location_obj.browse(vals['from_location'])
|
||||
to_location = location_obj.browse(vals['to_location'])
|
||||
product = product_obj.browse(vals['product'])
|
||||
if from_location.type == 'supplier' \
|
||||
and product.cost_price_method == 'average':
|
||||
self._update_product_cost_price(
|
||||
cursor, user, vals['product'], vals['quantity'],
|
||||
vals['uom'], vals['unit_price'], vals['currency'],
|
||||
vals['company'], context=context)
|
||||
self._update_product_cost_price(vals['product'],
|
||||
vals['quantity'], vals['uom'], vals['unit_price'],
|
||||
vals['currency'], vals['company'])
|
||||
if to_location.type == 'supplier' \
|
||||
and product.cost_price_method == 'average':
|
||||
self._update_product_cost_price(
|
||||
cursor, user, vals['product'], -vals['quantity'],
|
||||
vals['uom'], vals['unit_price'], vals['currency'],
|
||||
vals['company'], context=context)
|
||||
self._update_product_cost_price(vals['product'],
|
||||
-vals['quantity'], vals['uom'], vals['unit_price'],
|
||||
vals['currency'], vals['company'])
|
||||
if not vals.get('cost_price'):
|
||||
# Re-read product to get the updated cost_price
|
||||
product = product_obj.browse(cursor, user, vals['product'],
|
||||
context=context)
|
||||
product = product_obj.browse(vals['product'])
|
||||
vals['cost_price'] = product.cost_price
|
||||
|
||||
elif vals.get('state') == 'assigned':
|
||||
if not vals.get('effective_date'):
|
||||
vals['effective_date'] = date_obj.today(cursor, user,
|
||||
context=context)
|
||||
return super(Move, self).create(cursor, user, vals, context=context)
|
||||
vals['effective_date'] = date_obj.today()
|
||||
return super(Move, self).create(vals)
|
||||
|
||||
def write(self, cursor, user, ids, vals, context=None):
|
||||
def write(self, ids, vals):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
|
||||
if 'state' in vals:
|
||||
for move in self.browse(cursor, user, ids, context=context):
|
||||
for move in self.browse(ids):
|
||||
if vals['state'] == 'cancel':
|
||||
vals['effective_date'] = False
|
||||
if move.from_location.type == 'supplier' \
|
||||
and move.state != 'cancel' \
|
||||
and move.product.cost_price_method == 'average':
|
||||
self._update_product_cost_price(
|
||||
cursor, user, move.product.id, -move.quantity,
|
||||
move.uom, move.unit_price, move.currency,
|
||||
move.company, context=context)
|
||||
self._update_product_cost_price(move.product.id,
|
||||
-move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company)
|
||||
if move.to_location.type == 'supplier' \
|
||||
and move.state != 'cancel' \
|
||||
and move.product.cost_price_method == 'average':
|
||||
self._update_product_cost_price(
|
||||
cursor, user, move.product.id, move.quantity,
|
||||
move.uom, move.unit_price, move.currency,
|
||||
move.company, context=context)
|
||||
self._update_product_cost_price(move.product.id,
|
||||
move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company)
|
||||
|
||||
elif vals['state'] == 'draft':
|
||||
if move.state == 'done':
|
||||
self.raise_user_error(cursor, 'set_state_draft',
|
||||
context=context)
|
||||
self.raise_user_error('set_state_draft')
|
||||
elif vals['state'] == 'assigned':
|
||||
if move.state in ('cancel', 'done'):
|
||||
self.raise_user_error(cursor, 'set_state_assigned',
|
||||
context=context)
|
||||
vals['effective_date'] = date_obj.today(cursor, user,
|
||||
context=context)
|
||||
self.raise_user_error('set_state_assigned')
|
||||
vals['effective_date'] = date_obj.today()
|
||||
elif vals['state'] == 'done':
|
||||
if move.state in ('cancel'):
|
||||
self.raise_user_error(cursor, 'set_state_done',
|
||||
context=context)
|
||||
vals['effective_date'] = date_obj.today(cursor, user,
|
||||
context=context)
|
||||
self.raise_user_error('set_state_done')
|
||||
vals['effective_date'] = date_obj.today()
|
||||
|
||||
if move.from_location.type == 'supplier' \
|
||||
and move.state != 'done' \
|
||||
and move.product.cost_price_method == 'average':
|
||||
self._update_product_cost_price(
|
||||
cursor, user, move.product.id, move.quantity,
|
||||
move.uom, move.unit_price, move.currency,
|
||||
move.company, context=context)
|
||||
self._update_product_cost_price(move.product.id,
|
||||
move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company)
|
||||
if move.to_location.type == 'supplier' \
|
||||
and move.state != 'done' \
|
||||
and move.product.cost_price_method == 'average':
|
||||
self._update_product_cost_price(
|
||||
cursor, user, move.product.id, -move.quantity,
|
||||
move.uom, move.unit_price, move.currency,
|
||||
move.company, context=context)
|
||||
res = super(Move, self).write(cursor, user, ids, vals, context=context)
|
||||
self._update_product_cost_price( move.product.id,
|
||||
-move.quantity, move.uom, move.unit_price,
|
||||
move.currency, move.company)
|
||||
res = super(Move, self).write(ids, vals)
|
||||
|
||||
if vals.get('state', '') == 'done':
|
||||
#Re-read the move because cost_price has been updated
|
||||
for move in self.browse(cursor, user, ids, context=context):
|
||||
for move in self.browse(ids):
|
||||
if not move.cost_price:
|
||||
self.write(cursor, user, move.id, {
|
||||
self.write(move.id, {
|
||||
'cost_price': move.product.cost_price,
|
||||
}, context=context)
|
||||
})
|
||||
return res
|
||||
|
||||
def delete(self, cursor, user, ids, context=None):
|
||||
for move in self.browse(cursor, user, ids, context=context):
|
||||
def delete(self, ids):
|
||||
for move in self.browse(ids):
|
||||
if move.state not in ('draft', 'cancel'):
|
||||
self.raise_user_error(cursor, 'del_draft_cancel',
|
||||
context=context)
|
||||
return super(Move, self).delete(cursor, user, ids, context=context)
|
||||
self.raise_user_error('del_draft_cancel')
|
||||
return super(Move, self).delete(ids)
|
||||
|
||||
def pick_product(self, cursor, user, move, location_quantities, context=None):
|
||||
def pick_product(self, move, location_quantities):
|
||||
"""
|
||||
Pick the product across the location. Naive (fast) implementation.
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param move: a BrowseRecord of stock.move
|
||||
:param location_quantities: a list of tuple (location, available_qty)
|
||||
where location is a BrowseRecord of stock.location.
|
||||
:param context: the context
|
||||
:return: a list of tuple (location, quantity) for quantities
|
||||
that can be picked
|
||||
"""
|
||||
@@ -627,15 +550,12 @@ class Move(ModelSQL, ModelView):
|
||||
return to_pick
|
||||
return to_pick
|
||||
|
||||
def assign_try(self, cursor, user, moves, context=None):
|
||||
def assign_try(self, moves):
|
||||
'''
|
||||
Try to assign moves.
|
||||
It will split the moves to assign as much possible.
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param moves: a BrowseRecordList of stock.move to assign
|
||||
:param context: the context
|
||||
:return: True if succeed or False if not
|
||||
'''
|
||||
product_obj = self.pool.get('product.product')
|
||||
@@ -643,22 +563,16 @@ class Move(ModelSQL, ModelView):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
location_obj = self.pool.get('stock.location')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
Transaction().cursor.lock(self._table)
|
||||
|
||||
cursor.lock(self._table)
|
||||
|
||||
local_ctx = context and context.copy() or {}
|
||||
local_ctx['stock_date_end'] = date_obj.today(cursor, user,
|
||||
context=context)
|
||||
local_ctx['stock_assign'] = True
|
||||
location_ids = location_obj.search(cursor, user, [
|
||||
location_ids = location_obj.search([
|
||||
('parent', 'child_of', [x.from_location.id for x in moves]),
|
||||
], context=context)
|
||||
pbl = product_obj.products_by_location(cursor, user,
|
||||
location_ids=location_ids,
|
||||
product_ids=[m.product.id for m in moves],
|
||||
context=local_ctx)
|
||||
])
|
||||
with Transaction().set_context(
|
||||
stock_date_end=date_obj.today(),
|
||||
stock_assign=True):
|
||||
pbl = product_obj.products_by_location(location_ids=location_ids,
|
||||
product_ids=[m.product.id for m in moves])
|
||||
|
||||
success = True
|
||||
for move in moves:
|
||||
@@ -666,19 +580,17 @@ class Move(ModelSQL, ModelView):
|
||||
continue
|
||||
to_location = move.to_location
|
||||
location_qties = {}
|
||||
child_ids = location_obj.search(cursor, user, [
|
||||
child_ids = location_obj.search([
|
||||
('parent', 'child_of', [move.from_location.id]),
|
||||
], context=context)
|
||||
for location in location_obj.browse(cursor, user, child_ids,
|
||||
context=context):
|
||||
])
|
||||
for location in location_obj.browse(child_ids):
|
||||
if (location.id, move.product.id) in pbl:
|
||||
location_qties[location] = uom_obj.compute_qty(
|
||||
cursor, user, move.product.default_uom,
|
||||
pbl[(location.id, move.product.id)], move.uom,
|
||||
round=False, context=context)
|
||||
move.product.default_uom,
|
||||
pbl[(location.id, move.product.id)], move.uom,
|
||||
round=False)
|
||||
|
||||
to_pick = self.pick_product(
|
||||
cursor, user, move, location_qties, context=context)
|
||||
to_pick = self.pick_product(move, location_qties)
|
||||
|
||||
picked_qties = 0.0
|
||||
for _, qty in to_pick:
|
||||
@@ -687,9 +599,9 @@ class Move(ModelSQL, ModelView):
|
||||
if picked_qties < move.quantity:
|
||||
success = False
|
||||
first = False
|
||||
self.write(cursor, user, move.id, {
|
||||
self.write(move.id, {
|
||||
'quantity': move.quantity - picked_qties,
|
||||
}, context=context)
|
||||
})
|
||||
else:
|
||||
first = True
|
||||
for from_location, qty in to_pick:
|
||||
@@ -699,15 +611,13 @@ class Move(ModelSQL, ModelView):
|
||||
'state': 'assigned',
|
||||
}
|
||||
if first:
|
||||
self.write(cursor, user, move.id, values, context=context)
|
||||
self.write(move.id, values)
|
||||
first = False
|
||||
else:
|
||||
move_id = self.copy(cursor, user, move.id, default=values,
|
||||
context=context)
|
||||
move_id = self.copy(move.id, default=values)
|
||||
|
||||
qty_default_uom = uom_obj.compute_qty(
|
||||
cursor, user, move.uom, qty, move.product.default_uom,
|
||||
round=False, context=context)
|
||||
qty_default_uom = uom_obj.compute_qty(move.uom, qty,
|
||||
move.product.default_uom, round=False)
|
||||
|
||||
pbl[(from_location.id, move.product.id)] = \
|
||||
pbl.get((from_location.id, move.product.id), 0.0) - qty_default_uom
|
||||
|
||||
+88
-103
@@ -1,9 +1,11 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from __future__ import with_statement
|
||||
import datetime
|
||||
from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.wizard import Wizard
|
||||
from trytond.pyson import PYSONEncoder
|
||||
import datetime
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class Template(ModelSQL, ModelView):
|
||||
@@ -13,12 +15,12 @@ class Template(ModelSQL, ModelView):
|
||||
forecast_quantity = fields.Function(fields.Float('Forecast Quantity'),
|
||||
'get_quantity')
|
||||
|
||||
def get_quantity(self, cursor, user, ids, name, context=None):
|
||||
def get_quantity(self, ids, name):
|
||||
res = {}
|
||||
if name not in ('quantity', 'forecast_quantity'):
|
||||
raise Exception('Bad argument')
|
||||
|
||||
for template in self.browse(cursor, user, ids, context=context):
|
||||
for template in self.browse(ids):
|
||||
res[template.id] = 0.0
|
||||
for product in template.products:
|
||||
res[template.id] += product[name]
|
||||
@@ -31,29 +33,27 @@ class Template(ModelSQL, ModelView):
|
||||
'a product which is associated to stock moves.',
|
||||
})
|
||||
|
||||
def write(self, cursor, user, ids, vals, context=None):
|
||||
def write(self, ids, vals):
|
||||
move_obj = self.pool.get('stock.move')
|
||||
cursor = Transaction().cursor
|
||||
if not vals.get("default_uom"):
|
||||
return super(Template, self).write(cursor, user, ids, vals,
|
||||
context=context)
|
||||
return super(Template, self).write(ids, vals)
|
||||
|
||||
for i in range(0, len(ids), cursor.IN_MAX):
|
||||
sub_ids = ids[i:i + cursor.IN_MAX]
|
||||
res = self.search(cursor, user, [
|
||||
res = self.search([
|
||||
('id', 'in', sub_ids),
|
||||
('default_uom', '!=', vals['default_uom']),
|
||||
], context=context)
|
||||
])
|
||||
|
||||
if res:
|
||||
res = move_obj.search(cursor, user, [
|
||||
res = move_obj.search([
|
||||
('product.template', 'in', res),
|
||||
], limit=1, context=context)
|
||||
], limit=1)
|
||||
if res:
|
||||
self.raise_user_error(cursor, 'change_default_uom',
|
||||
context=context)
|
||||
self.raise_user_error('change_default_uom')
|
||||
|
||||
return super(Template, self).write(cursor, user, ids, vals,
|
||||
context=context)
|
||||
return super(Template, self).write(ids, vals)
|
||||
|
||||
|
||||
Template()
|
||||
@@ -66,32 +66,30 @@ class Product(ModelSQL, ModelView):
|
||||
forecast_quantity = fields.Function(fields.Float('Forecast Quantity'),
|
||||
'get_quantity', searcher='search_quantity')
|
||||
|
||||
def get_quantity(self, cursor, user, ids, name, context=None):
|
||||
def get_quantity(self, ids, name):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
|
||||
if not (context and context.get('locations')):
|
||||
return dict([(id, 0.0) for id in ids])
|
||||
if not Transaction().context.get('locations'):
|
||||
return dict((id, 0.0) for id in ids)
|
||||
|
||||
if name == 'quantity' and \
|
||||
context.get('stock_date_end') and \
|
||||
context.get('stock_date_end') > \
|
||||
date_obj.today(cursor, user, context=context):
|
||||
|
||||
context = context.copy()
|
||||
context['stock_date_end'] = date_obj.today(
|
||||
cursor, user, context=context)
|
||||
context = {}
|
||||
if (name == 'quantity'
|
||||
and Transaction().context.get('stock_date_end')
|
||||
and Transaction().context.get('stock_date_end') >
|
||||
date_obj.today()):
|
||||
context['stock_date_end'] = date_obj.today()
|
||||
|
||||
if name == 'forecast_quantity':
|
||||
context = context.copy()
|
||||
context['forecast'] = True
|
||||
if not context.get('stock_date_end'):
|
||||
if not Transaction().context.get('stock_date_end'):
|
||||
context['stock_date_end'] = datetime.date.max
|
||||
pbl = self.products_by_location(cursor, user,
|
||||
location_ids=context['locations'], product_ids=ids,
|
||||
with_childs=True, context=context)
|
||||
with Transaction().set_context(context):
|
||||
pbl = self.products_by_location(
|
||||
location_ids=Transaction().context['locations'],
|
||||
product_ids=ids, with_childs=True)
|
||||
|
||||
res = {}.fromkeys(ids, 0.0)
|
||||
for location in context['locations']:
|
||||
for location in Transaction().context['locations']:
|
||||
for product in ids:
|
||||
res[product] += pbl.get((location, product), 0.0)
|
||||
return res
|
||||
@@ -107,30 +105,28 @@ class Product(ModelSQL, ModelView):
|
||||
operator= "=="
|
||||
return (eval(str(value) + operator + str(operand)))
|
||||
|
||||
def search_quantity(self, cursor, user, name, domain=None, context=None):
|
||||
def search_quantity(self, name, domain=None):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
|
||||
if not (context and context.get('locations') and domain):
|
||||
if not (Transaction().context.get('locations') and domain):
|
||||
return []
|
||||
|
||||
if name == 'quantity' and \
|
||||
context.get('stock_date_end') and \
|
||||
context.get('stock_date_end') > \
|
||||
date_obj.today(cursor, user, context=context):
|
||||
|
||||
context = context.copy()
|
||||
context['stock_date_end'] = date_obj.today(
|
||||
cursor, user, context=context)
|
||||
context = {}
|
||||
if (name == 'quantity'
|
||||
and Transaction().context.get('stock_date_end')
|
||||
and Transaction().context.get('stock_date_end') >
|
||||
date_obj.today()):
|
||||
context['stock_date_end'] = date_obj.today()
|
||||
|
||||
if name == 'forecast_quantity':
|
||||
context = context.copy()
|
||||
context['forecast'] = True
|
||||
if not context.get('stock_date_end'):
|
||||
if not Transaction().context.get('stock_date_end'):
|
||||
context['stock_date_end'] = datetime.date.max
|
||||
|
||||
pbl = self.products_by_location(
|
||||
cursor, user, location_ids=context['locations'], with_childs=True,
|
||||
skip_zero=False, context=context).iteritems()
|
||||
with Transaction().set_context(context):
|
||||
pbl = self.products_by_location(
|
||||
location_ids=Transaction().context['locations'],
|
||||
with_childs=True, skip_zero=False).iteritems()
|
||||
|
||||
processed_lines = []
|
||||
for (location, product), quantity in pbl:
|
||||
@@ -144,20 +140,13 @@ class Product(ModelSQL, ModelView):
|
||||
|
||||
|
||||
|
||||
def products_by_location(self, cursor, user, location_ids,
|
||||
product_ids=None, with_childs=False, skip_zero=True, context=None):
|
||||
def products_by_location(self, location_ids, product_ids=None,
|
||||
with_childs=False, skip_zero=True):
|
||||
"""
|
||||
Compute for each location and product the stock quantity in the default
|
||||
uom of the product.
|
||||
|
||||
:param cursor: the database cursor
|
||||
:param user: the user id
|
||||
:param location_ids: the ids of locations
|
||||
:param product_ids: the ids of the products
|
||||
if None all products are used
|
||||
:param with_childs: a boolean to compute also for child locations
|
||||
:param skip_zero: a boolean to list also items with zero quantity
|
||||
:param context: the context with keys:
|
||||
The context with keys:
|
||||
stock_date_end: if set the date of the stock computation.
|
||||
stock_date_start: if set return the delta of the stock
|
||||
between the two dates, (ignored if stock_date_end is
|
||||
@@ -169,6 +158,12 @@ class Product(ModelSQL, ModelView):
|
||||
stock_skip_warehouse: if set, quantities on a warehouse are no
|
||||
more quantities of all child locations but quantities of the
|
||||
storage zone.
|
||||
|
||||
:param location_ids: the ids of locations
|
||||
:param product_ids: the ids of the products
|
||||
if None all products are used
|
||||
:param with_childs: a boolean to compute also for child locations
|
||||
:param skip_zero: a boolean to list also items with zero quantity
|
||||
:return: a dictionary with (location id, product id) as key
|
||||
and quantity as value
|
||||
"""
|
||||
@@ -178,22 +173,21 @@ class Product(ModelSQL, ModelView):
|
||||
location_obj = self.pool.get('stock.location')
|
||||
date_obj = self.pool.get('ir.date')
|
||||
|
||||
today = date_obj.today(cursor, user, context=context)
|
||||
today = date_obj.today()
|
||||
|
||||
if not location_ids:
|
||||
return {}
|
||||
if context is None:
|
||||
context= {}
|
||||
cursor = Transaction().cursor
|
||||
context = Transaction().context.copy()
|
||||
# Skip warehouse location in favor of their storage location
|
||||
# to compute quantities. Keep track of which ids to remove
|
||||
# and to add after the query.
|
||||
location_ids = set(location_ids)
|
||||
storage_to_remove = set()
|
||||
wh_to_add = {}
|
||||
for location in location_obj.browse(
|
||||
cursor, user, location_ids, context=context):
|
||||
if location.type == 'warehouse' \
|
||||
and context.get('stock_skip_warehouse'):
|
||||
for location in location_obj.browse(location_ids):
|
||||
if (location.type == 'warehouse'
|
||||
and Transaction().context.get('stock_skip_warehouse')):
|
||||
location_ids.remove(location.id)
|
||||
if location.storage_location.id not in location_ids:
|
||||
storage_to_remove.add(location.storage_location.id)
|
||||
@@ -201,17 +195,15 @@ class Product(ModelSQL, ModelView):
|
||||
wh_to_add[location.id] = location.storage_location.id
|
||||
location_ids = list(location_ids)
|
||||
|
||||
move_query, move_val = rule_obj.domain_get(cursor, user, 'stock.move',
|
||||
context=context)
|
||||
move_query, move_val = rule_obj.domain_get('stock.move')
|
||||
|
||||
if not context.get('stock_date_end'):
|
||||
context = context.copy()
|
||||
context['stock_date_end'] = datetime.date.max
|
||||
|
||||
# date end in the past or today: filter on state done
|
||||
if context['stock_date_end'] < today or \
|
||||
(context['stock_date_end'] == today \
|
||||
and not context.get('forecast')):
|
||||
if (context['stock_date_end'] < today
|
||||
or (context['stock_date_end'] == today
|
||||
and not context.get('forecast'))):
|
||||
state_date_clause = \
|
||||
'('\
|
||||
'(state in (%s, %s)) '\
|
||||
@@ -359,9 +351,9 @@ class Product(ModelSQL, ModelView):
|
||||
])
|
||||
|
||||
if with_childs:
|
||||
query, args = location_obj.search(cursor, user, [
|
||||
query, args = location_obj.search([
|
||||
('parent', 'child_of', location_ids),
|
||||
], context=context, query_string=True, order=[])
|
||||
], query_string=True, order=[])
|
||||
where_clause = " IN (" + query + ") "
|
||||
where_vals = args
|
||||
else:
|
||||
@@ -442,27 +434,24 @@ class Product(ModelSQL, ModelView):
|
||||
if line[position] not in id_list:
|
||||
id_list.append(line[position])
|
||||
|
||||
uom_by_id = dict([(x.id, x) for x in uom_obj.browse(
|
||||
cursor, user, uom_ids, context=context)])
|
||||
uom_by_id = dict((x.id, x) for x in uom_obj.browse(uom_ids))
|
||||
default_uom = dict((x.id, x.default_uom) for x in product_obj.browse(
|
||||
cursor, user, product_ids or res_product_ids, context=context))
|
||||
product_ids or res_product_ids))
|
||||
|
||||
for line in raw_lines:
|
||||
location, product, uom, quantity = line
|
||||
key = (location, product)
|
||||
res.setdefault(key, 0.0)
|
||||
res[key] += uom_obj.compute_qty(cursor, user, uom_by_id[uom],
|
||||
quantity, default_uom[product], round=False,
|
||||
context=context)
|
||||
res[key] += uom_obj.compute_qty(uom_by_id[uom], quantity,
|
||||
default_uom[product], round=False)
|
||||
|
||||
# Propagate quantities on from child locations to their parents
|
||||
if with_childs:
|
||||
# Fetch all child locations
|
||||
all_location_ids = location_obj.search(
|
||||
cursor, user, [('parent', 'child_of', location_ids)],
|
||||
context=context)
|
||||
locations = location_obj.browse(cursor, user, all_location_ids,
|
||||
context=context)
|
||||
all_location_ids = location_obj.search([
|
||||
('parent', 'child_of', location_ids),
|
||||
])
|
||||
locations = location_obj.browse(all_location_ids)
|
||||
# Generate a set of locations without childs and a dict
|
||||
# giving the parent of each location.
|
||||
leafs = set(all_location_ids)
|
||||
@@ -492,9 +481,8 @@ class Product(ModelSQL, ModelView):
|
||||
# Round quantities
|
||||
for location, product in res:
|
||||
key = (location, product)
|
||||
res[key] = uom_obj.compute_qty(cursor, user, default_uom[product],
|
||||
res[key], default_uom[product], round=True,
|
||||
context=context)
|
||||
res[key] = uom_obj.compute_qty(default_uom[product], res[key],
|
||||
default_uom[product], round=True)
|
||||
|
||||
# Complete result with missing products if asked
|
||||
if not skip_zero:
|
||||
@@ -502,8 +490,7 @@ class Product(ModelSQL, ModelView):
|
||||
if product_ids:
|
||||
all_product_ids = product_ids
|
||||
else:
|
||||
all_product_ids = self.pool.get("product.product").search(
|
||||
cursor, user, [], context=context)
|
||||
all_product_ids = self.pool.get("product.product").search([])
|
||||
keys = ((l,p) for l in location_ids for p in all_product_ids)
|
||||
for location_id, product_id in keys:
|
||||
if (location_id, product_id) not in res:
|
||||
@@ -519,13 +506,11 @@ class Product(ModelSQL, ModelView):
|
||||
|
||||
return res
|
||||
|
||||
def view_header_get(self, cursor, user, value, view_type='form',
|
||||
context=None):
|
||||
if not context.get('locations'):
|
||||
def view_header_get(self, value, view_type='form'):
|
||||
if not Transaction().context.get('locations'):
|
||||
return value
|
||||
location_obj = self.pool.get('stock.location')
|
||||
locations = location_obj.browse(cursor, user, context.get('locations'),
|
||||
context=context)
|
||||
locations = location_obj.browse(Transaction().context.get('locations'))
|
||||
return value + " (" + ",".join(l.name for l in locations) + ")"
|
||||
|
||||
Product()
|
||||
@@ -540,9 +525,9 @@ class ChooseStockDateInit(ModelView):
|
||||
'* An empty value is an infinite date in the future.\n'\
|
||||
'* A date in the past will provide historical values.')
|
||||
|
||||
def default_forecast_date(self, cursor, user, context=None):
|
||||
def default_forecast_date(self):
|
||||
date_obj = self.pool.get('ir.date')
|
||||
return date_obj.today(cursor, user, context=context)
|
||||
return date_obj.today()
|
||||
|
||||
ChooseStockDateInit()
|
||||
|
||||
@@ -569,20 +554,20 @@ class OpenLocation(Wizard):
|
||||
},
|
||||
}
|
||||
|
||||
def _action_open_location(self, cursor, user, data, context=None):
|
||||
def _action_open_location(self, data):
|
||||
model_data_obj = self.pool.get('ir.model.data')
|
||||
act_window_obj = self.pool.get('ir.action.act_window')
|
||||
act_window_id = model_data_obj.get_id(cursor, user, 'stock',
|
||||
'act_location_quantity_tree', context=context)
|
||||
res = act_window_obj.read(cursor, user, act_window_id, context=context)
|
||||
act_window_id = model_data_obj.get_id('stock',
|
||||
'act_location_quantity_tree')
|
||||
res = act_window_obj.read(act_window_id)
|
||||
|
||||
ctx = {}
|
||||
ctx['product'] = data['id']
|
||||
context = {}
|
||||
context['product'] = data['id']
|
||||
if data['form']['forecast_date']:
|
||||
ctx['stock_date_end'] = data['form']['forecast_date']
|
||||
context['stock_date_end'] = data['form']['forecast_date']
|
||||
else:
|
||||
ctx['stock_date_end'] = datetime.date.max
|
||||
res['pyson_context'] = PYSONEncoder().encode(ctx)
|
||||
context['stock_date_end'] = datetime.date.max
|
||||
res['pyson_context'] = PYSONEncoder().encode(context)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
+501
-583
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user