577 lines
24 KiB
Diff
577 lines
24 KiB
Diff
diff --git a/move.py b/move.py
|
|
index 1d4bd63..1b41353 100644
|
|
--- a/trytond/trytond/modules/product_cost_fifo/move.py
|
|
+++ b/trytond/trytond/modules/product_cost_fifo/move.py
|
|
@@ -10,6 +10,8 @@ from trytond.model.exceptions import AccessError
|
|
from trytond.pool import Pool, PoolMeta
|
|
from trytond.transaction import Transaction
|
|
|
|
+from trytond.modules.product import round_price
|
|
+
|
|
__all__ = ['Move']
|
|
|
|
|
|
@@ -60,6 +62,24 @@ class Move(metaclass=PoolMeta):
|
|
column, operator, value, expression)
|
|
return expression
|
|
|
|
+ def _compute_product_cost_price(self, direction, product_cost_price=None):
|
|
+ pool = Pool()
|
|
+ Location = pool.get('stock.location')
|
|
+ Config = pool.get('stock.configuration')
|
|
+
|
|
+ configuration = Config(1)
|
|
+ location_ids = []
|
|
+
|
|
+ if configuration.warehouse:
|
|
+ locations = Location.search([
|
|
+ ('parent', 'child_of', [configuration.warehouse]),
|
|
+ ])
|
|
+ location_ids = list(set(x.id for x in locations))
|
|
+ with Transaction().set_context(locations=location_ids):
|
|
+ self = self.__class__(self.id)
|
|
+ return super()._compute_product_cost_price(direction,
|
|
+ product_cost_price)
|
|
+
|
|
def _update_fifo_out_product_cost_price(self):
|
|
'''
|
|
Update the product cost price of the given product on the move. Update
|
|
@@ -68,7 +88,6 @@ class Move(metaclass=PoolMeta):
|
|
'''
|
|
pool = Pool()
|
|
Uom = pool.get('product.uom')
|
|
- Currency = pool.get('currency.currency')
|
|
|
|
total_qty = Uom.compute_qty(self.uom, self.quantity,
|
|
self.product.default_uom, round=False)
|
|
@@ -81,16 +100,7 @@ class Move(metaclass=PoolMeta):
|
|
to_save = []
|
|
for move, move_qty in fifo_moves:
|
|
consumed_qty += move_qty
|
|
- if move.from_location.type in {'supplier', 'production'}:
|
|
- with Transaction().set_context(date=move.effective_date):
|
|
- move_unit_price = Currency.compute(
|
|
- move.currency, move.unit_price,
|
|
- self.company.currency, round=False)
|
|
- move_unit_price = Uom.compute_price(
|
|
- move.uom, move_unit_price, move.product.default_uom)
|
|
- else:
|
|
- move_unit_price = move.cost_price or 0
|
|
- cost_price += move_unit_price * Decimal(str(move_qty))
|
|
+ cost_price += move.get_cost_price() * Decimal(str(move_qty))
|
|
|
|
move_qty = Uom.compute_qty(self.product.default_uom, move_qty,
|
|
move.uom, round=False)
|
|
@@ -107,23 +117,18 @@ class Move(metaclass=PoolMeta):
|
|
'cost_price', **self._cost_price_pattern)
|
|
|
|
# Compute average cost price
|
|
- unit_price = self.unit_price
|
|
- self.unit_price = Uom.compute_price(
|
|
- self.product.default_uom, cost_price, self.uom)
|
|
- average_cost_price = self._compute_product_cost_price('out')
|
|
- self.unit_price = unit_price
|
|
+ average_cost_price = self._compute_product_cost_price(
|
|
+ 'out', product_cost_price=cost_price)
|
|
|
|
if cost_price:
|
|
- digits = self.__class__.cost_price.digits
|
|
- cost_price = cost_price.quantize(
|
|
- Decimal(str(10.0 ** -digits[1])))
|
|
+ cost_price = round_price(cost_price)
|
|
else:
|
|
cost_price = average_cost_price
|
|
return cost_price, average_cost_price
|
|
|
|
def _do(self):
|
|
cost_price = super(Move, self)._do()
|
|
- if (self.from_location.type in ('supplier', 'production')
|
|
+ if (self.from_location.type != 'storage'
|
|
and self.to_location.type == 'storage'
|
|
and self.product.cost_price_method == 'fifo'):
|
|
cost_price = self._compute_product_cost_price('in')
|
|
@@ -136,7 +141,7 @@ class Move(metaclass=PoolMeta):
|
|
and self.product.cost_price_method == 'fifo'):
|
|
fifo_cost_price, cost_price = (
|
|
self._update_fifo_out_product_cost_price())
|
|
- if self.cost_price is None:
|
|
+ if self.cost_price_required and self.cost_price is None:
|
|
self.cost_price = fifo_cost_price
|
|
return cost_price
|
|
|
|
diff --git a/product.py b/product.py
|
|
index 9eaceac..aa1b06c 100644
|
|
--- a/trytond/trytond/modules/product_cost_fifo/product.py
|
|
+++ b/trytond/trytond/modules/product_cost_fifo/product.py
|
|
@@ -7,6 +7,8 @@ from trytond.config import config
|
|
from trytond.transaction import Transaction
|
|
from trytond.pool import Pool, PoolMeta
|
|
|
|
+from trytond.modules.product import round_price
|
|
+
|
|
__all__ = ['Template', 'Product']
|
|
|
|
|
|
@@ -24,6 +26,49 @@ class Template(metaclass=PoolMeta):
|
|
class Product(metaclass=PoolMeta):
|
|
__name__ = 'product.product'
|
|
|
|
+ def _extra_domain_fifo_moves(self):
|
|
+ pool = Pool()
|
|
+ Location = pool.get('stock.location')
|
|
+ Config = pool.get('stock.configuration')
|
|
+
|
|
+ configuration = Config(1)
|
|
+
|
|
+ domain = []
|
|
+ if configuration.warehouse:
|
|
+ storage_locations = Location.search(['type', '=', 'storage'])
|
|
+ locations = Location.search([
|
|
+ ('parent', 'child_of', [configuration.warehouse]),
|
|
+ ])
|
|
+ location_ids = list(set(x.id for x in storage_locations) -
|
|
+ set(x.id for x in locations))
|
|
+ domain.extend([
|
|
+ ('to_location.id', 'not in', location_ids),
|
|
+ ('from_location.id', 'not in', location_ids),
|
|
+ ])
|
|
+ return domain
|
|
+
|
|
+ def _get_storage_quantity(self, date=None):
|
|
+ pool = Pool()
|
|
+ Location = pool.get('stock.location')
|
|
+ Config = pool.get('stock.configuration')
|
|
+
|
|
+ configuration = Config(1)
|
|
+
|
|
+ if not configuration.warehouse:
|
|
+ return super()._get_storage_quantity(date)
|
|
+
|
|
+ locations = Location.search([
|
|
+ ('parent', 'child_of', [configuration.warehouse]),
|
|
+ ])
|
|
+ if not date:
|
|
+ date = dt.date.today()
|
|
+ location_ids = [l.id for l in locations]
|
|
+ with Transaction().set_context(
|
|
+ locations=location_ids,
|
|
+ with_childs=False,
|
|
+ stock_date_end=date):
|
|
+ return self.__class__(self.id).quantity
|
|
+
|
|
def _get_available_fifo_moves(self, date=None, offset=0, limit=None):
|
|
pool = Pool()
|
|
Move = pool.get('stock.move')
|
|
@@ -31,13 +76,16 @@ class Product(metaclass=PoolMeta):
|
|
domain = [
|
|
('product', '=', self.id),
|
|
self._domain_moves_cost(),
|
|
- ('from_location.type', 'in', ['supplier', 'production']),
|
|
+ ('from_location.type', '!=', 'storage'),
|
|
('to_location.type', '=', 'storage'),
|
|
]
|
|
if not date:
|
|
domain.append(('fifo_quantity_available', '>', 0))
|
|
else:
|
|
domain.append(('effective_date', '<=', date))
|
|
+ if self._extra_domain_fifo_moves():
|
|
+ domain.extend(self._extra_domain_fifo_moves())
|
|
+
|
|
return Move.search(
|
|
domain,
|
|
offset=offset, limit=limit,
|
|
@@ -93,9 +141,7 @@ class Product(metaclass=PoolMeta):
|
|
def recompute_cost_price_fifo(self, start=None):
|
|
pool = Pool()
|
|
Move = pool.get('stock.move')
|
|
- Currency = pool.get('currency.currency')
|
|
Uom = pool.get('product.uom')
|
|
- digits = self.__class__.cost_price.digits
|
|
|
|
domain = [
|
|
('product', '=', self.id),
|
|
@@ -113,6 +159,8 @@ class Product(metaclass=PoolMeta):
|
|
]
|
|
if start:
|
|
domain.append(('effective_date', '>=', start))
|
|
+ if self._extra_domain_fifo_moves():
|
|
+ domain.extend(self._extra_domain_fifo_moves())
|
|
moves = Move.search(
|
|
domain, order=[('effective_date', 'ASC'), ('id', 'ASC')])
|
|
|
|
@@ -135,32 +183,27 @@ class Product(metaclass=PoolMeta):
|
|
quantity = Decimal(str(quantity))
|
|
|
|
def in_move(move):
|
|
- return (move.from_location.type in ['supplier', 'production']
|
|
- or move.to_location.type == 'supplier')
|
|
+ return move.to_location.type == 'storage'
|
|
|
|
def out_move(move):
|
|
- return not in_move(move)
|
|
+ return move.from_location.type == 'storage'
|
|
|
|
def compute_fifo_cost_price(quantity, date):
|
|
- fifo_moves = self.get_fifo_move(
|
|
- float(quantity),
|
|
- date=current_moves[-1].effective_date)
|
|
+ fifo_moves = self.get_fifo_move(float(quantity), date=date)
|
|
|
|
cost_price = Decimal(0)
|
|
consumed_qty = 0
|
|
for move, move_qty in fifo_moves:
|
|
consumed_qty += move_qty
|
|
- with Transaction().set_context(date=move.effective_date):
|
|
- unit_price = Currency.compute(
|
|
- move.currency, move.unit_price,
|
|
- move.company.currency, round=False)
|
|
- unit_price = Uom.compute_price(
|
|
- move.uom, unit_price, move.product.default_uom)
|
|
- cost_price += unit_price * Decimal(str(move_qty))
|
|
+ cost_price += move.get_cost_price() * Decimal(str(move_qty))
|
|
if consumed_qty:
|
|
- return (cost_price / Decimal(str(consumed_qty))).quantize(
|
|
- Decimal(str(10.0 ** -digits[1])))
|
|
+ return round_price(cost_price / Decimal(str(consumed_qty)))
|
|
|
|
+ # Process first the incoming per day
|
|
+ # in order to keep quantity positive as much as possible
|
|
+ # We do no re-browse because we expect only few permutations
|
|
+ moves = sorted(moves, key=lambda m: (
|
|
+ m.effective_date, out_move(m), m.id))
|
|
current_moves = []
|
|
current_out_qty = 0
|
|
current_cost_price = cost_price
|
|
@@ -183,42 +226,33 @@ class Product(metaclass=PoolMeta):
|
|
m for m in out_moves
|
|
if m.cost_price != fifo_cost_price],
|
|
dict(cost_price=fifo_cost_price))
|
|
- if quantity:
|
|
+ if quantity > 0 and quantity + current_out_qty >= 0:
|
|
cost_price = (
|
|
((current_cost_price * (
|
|
quantity + current_out_qty))
|
|
- (fifo_cost_price * current_out_qty))
|
|
/ quantity)
|
|
else:
|
|
- cost_price = Decimal(0)
|
|
- current_cost_price = cost_price.quantize(
|
|
- Decimal(str(10.0 ** -digits[1])))
|
|
+ cost_price = current_cost_price
|
|
+ current_cost_price = round_price(cost_price)
|
|
current_moves.clear()
|
|
current_out_qty = 0
|
|
current_moves.append(move)
|
|
|
|
qty = Uom.compute_qty(move.uom, move.quantity, self.default_uom)
|
|
qty = Decimal(str(qty))
|
|
- if move.from_location.type == 'storage':
|
|
- qty *= -1
|
|
if in_move(move):
|
|
- with Transaction().set_context(date=move.effective_date):
|
|
- unit_price = Currency.compute(
|
|
- move.currency, move.unit_price,
|
|
- move.company.currency, round=False)
|
|
- unit_price = Uom.compute_price(
|
|
- move.uom, unit_price, self.default_uom)
|
|
+ unit_price = move.get_cost_price(product_cost_price=cost_price)
|
|
if quantity + qty > 0 and quantity >= 0:
|
|
cost_price = (
|
|
(cost_price * quantity) + (unit_price * qty)
|
|
) / (quantity + qty)
|
|
elif qty > 0:
|
|
cost_price = unit_price
|
|
- current_cost_price = cost_price.quantize(
|
|
- Decimal(str(10.0 ** -digits[1])))
|
|
- else:
|
|
- current_out_qty += -qty
|
|
- quantity += qty
|
|
+ current_cost_price = round_price(cost_price)
|
|
+ elif out_move(move):
|
|
+ current_out_qty += qty
|
|
+ quantity += -qty if out_move(move) else qty
|
|
|
|
Move.write([
|
|
m for m in filter(in_move, current_moves)
|
|
@@ -235,14 +269,10 @@ class Product(metaclass=PoolMeta):
|
|
m for m in out_moves
|
|
if m.cost_price != fifo_cost_price],
|
|
dict(cost_price=fifo_cost_price))
|
|
- if quantity:
|
|
+ if quantity > 0 and quantity + current_out_qty >= 0:
|
|
cost_price = (
|
|
((current_cost_price * (
|
|
quantity + current_out_qty))
|
|
- (fifo_cost_price * current_out_qty))
|
|
/ quantity)
|
|
- else:
|
|
- cost_price = Decimal(0)
|
|
- current_cost_price = cost_price.quantize(
|
|
- Decimal(str(10.0 ** -digits[1])))
|
|
- return current_cost_price
|
|
+ return cost_price
|
|
diff --git a/tests/scenario_product_cost_fifo_recompute_cost_price.rst b/tests/scenario_product_cost_fifo_recompute_cost_price.rst
|
|
index f8b952f..d4f906d 100644
|
|
--- a/trytond/trytond/modules/product_cost_fifo/tests/scenario_product_cost_fifo_recompute_cost_price.rst
|
|
+++ b/trytond/trytond/modules/product_cost_fifo/tests/scenario_product_cost_fifo_recompute_cost_price.rst
|
|
@@ -45,6 +45,7 @@ Get stock locations::
|
|
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
|
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
|
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
|
+ >>> lost_found, = Location.find([('name', '=', "Lost and Found")])
|
|
|
|
Create some moves::
|
|
|
|
@@ -58,6 +59,12 @@ Create some moves::
|
|
... effective_date=today - dt.timedelta(days=2)).click('do')
|
|
>>> StockMove(
|
|
... product=product,
|
|
+ ... quantity=1,
|
|
+ ... from_location=lost_found,
|
|
+ ... to_location=storage_loc,
|
|
+ ... effective_date=today - dt.timedelta(days=1)).click('do')
|
|
+ >>> StockMove(
|
|
+ ... product=product,
|
|
... quantity=2,
|
|
... from_location=supplier_loc,
|
|
... to_location=storage_loc,
|
|
@@ -67,8 +74,7 @@ Create some moves::
|
|
... product=product,
|
|
... quantity=2,
|
|
... from_location=storage_loc,
|
|
- ... to_location=customer_loc,
|
|
- ... unit_price=Decimal('300'),
|
|
+ ... to_location=lost_found,
|
|
... effective_date=today - dt.timedelta(days=1)).click('do')
|
|
>>> StockMove(
|
|
... product=product,
|
|
@@ -94,11 +100,11 @@ Create some moves::
|
|
|
|
|
|
>>> [m.cost_price for m in StockMove.find([])]
|
|
- [Decimal('100.0000'), Decimal('110.0000'), Decimal('105.0000'), Decimal('110.0000'), Decimal('113.3333'), Decimal('100.0000')]
|
|
+ [Decimal('100.0000'), Decimal('116.6666'), Decimal('106.6666'), Decimal('110.0000'), Decimal('113.3333'), Decimal('113.3333'), Decimal('100.0000')]
|
|
|
|
>>> product.reload()
|
|
>>> product.cost_price
|
|
- Decimal('100.0000')
|
|
+ Decimal('99.9998')
|
|
|
|
Recompute cost price::
|
|
|
|
@@ -106,11 +112,11 @@ Recompute cost price::
|
|
>>> recompute.execute('recompute')
|
|
|
|
>>> [m.cost_price for m in StockMove.find([])]
|
|
- [Decimal('106.6667'), Decimal('106.6667'), Decimal('105.0000'), Decimal('110.0000'), Decimal('113.3333'), Decimal('100.0000')]
|
|
+ [Decimal('111.1111'), Decimal('111.1111'), Decimal('106.6666'), Decimal('110.0000'), Decimal('113.3333'), Decimal('113.3333'), Decimal('100.0000')]
|
|
|
|
>>> product.reload()
|
|
>>> product.cost_price
|
|
- Decimal('99.9999')
|
|
+ Decimal('100.0000')
|
|
|
|
Recompute cost price from a date::
|
|
|
|
@@ -119,8 +125,8 @@ Recompute cost price from a date::
|
|
>>> recompute.execute('recompute')
|
|
|
|
>>> [m.cost_price for m in StockMove.find([])]
|
|
- [Decimal('106.6667'), Decimal('106.6667'), Decimal('105.0000'), Decimal('110.0000'), Decimal('113.3333'), Decimal('100.0000')]
|
|
+ [Decimal('111.1111'), Decimal('111.1111'), Decimal('106.6666'), Decimal('110.0000'), Decimal('113.3333'), Decimal('113.3333'), Decimal('100.0000')]
|
|
|
|
>>> product.reload()
|
|
>>> product.cost_price
|
|
- Decimal('99.9999')
|
|
+ Decimal('100.0000')
|
|
diff --git a/stock.py b/stock.py
|
|
index c7b247f..34e7d47 100644
|
|
--- a/trytond/trytond/modules/sale/stock.py
|
|
+++ b/trytond/trytond/modules/sale/stock.py
|
|
@@ -1,6 +1,7 @@
|
|
# 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 functools import wraps
|
|
+from decimal import Decimal
|
|
|
|
from trytond.i18n import gettext
|
|
from trytond.model import Workflow, ModelView, fields
|
|
@@ -8,6 +9,8 @@ from trytond.model.exceptions import AccessError
|
|
from trytond.transaction import Transaction
|
|
from trytond.pool import Pool, PoolMeta
|
|
|
|
+from trytond.modules.product import round_price
|
|
+
|
|
__all__ = ['ShipmentOut', 'ShipmentOutReturn', 'Move']
|
|
|
|
|
|
@@ -155,6 +158,33 @@ class Move(metaclass=PoolMeta):
|
|
category = self.origin.unit.category.id
|
|
return category
|
|
|
|
+ def get_cost_price(self, product_cost_price=None):
|
|
+ pool = Pool()
|
|
+ SaleLine = pool.get('sale.line')
|
|
+ Sale = pool.get('sale.sale')
|
|
+ # For return sale's move use the cost price of the original sale
|
|
+ if (isinstance(self.origin, SaleLine)
|
|
+ and self.origin.quantity < 0
|
|
+ and self.from_location.type != 'storage'
|
|
+ and self.to_location.type == 'storage'
|
|
+ and isinstance(self.origin.sale.origin, Sale)):
|
|
+ sale = self.origin.sale.origin
|
|
+ cost = Decimal(0)
|
|
+ qty = Decimal(0)
|
|
+ for move in sale.moves:
|
|
+ if (move.state == 'done'
|
|
+ and move.from_location.type == 'storage'
|
|
+ and move.to_location.type == 'customer'
|
|
+ and move.product == self.product):
|
|
+ move_quantity = Decimal(str(move.internal_quantity))
|
|
+ cost_price = move.get_cost_price(
|
|
+ product_cost_price=move.cost_price)
|
|
+ qty += move_quantity
|
|
+ cost += cost_price * move_quantity
|
|
+ if qty:
|
|
+ product_cost_price = round_price(cost / qty)
|
|
+ return super().get_cost_price(product_cost_price=product_cost_price)
|
|
+
|
|
@property
|
|
def origin_name(self):
|
|
pool = Pool()
|
|
diff --git a/move.py b/move.py
|
|
index aafa9e8..4ed02e7 100644
|
|
--- a/trytond/trytond/modules/stock/move.py
|
|
+++ b/trytond/trytond/modules/stock/move.py
|
|
@@ -19,7 +19,7 @@ from trytond.tools import reduce_ids
|
|
from trytond.transaction import Transaction
|
|
from trytond.pool import Pool
|
|
|
|
-from trytond.modules.product import price_digits
|
|
+from trytond.modules.product import price_digits, round_price
|
|
|
|
from .exceptions import MoveOriginWarning
|
|
|
|
@@ -251,8 +251,15 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
'invisible': Eval('state') != 'done',
|
|
},
|
|
depends=['state'])
|
|
- cost_price = fields.Numeric('Cost Price', digits=price_digits,
|
|
- readonly=True)
|
|
+ cost_price = fields.Numeric(
|
|
+ "Cost Price", digits=price_digits, readonly=True,
|
|
+ states={
|
|
+ 'invisible': ~Eval('cost_price_required'),
|
|
+ 'required': (
|
|
+ (Eval('state') == 'done')
|
|
+ & Eval('cost_price_required', False)),
|
|
+ },
|
|
+ depends=['cost_price_required'])
|
|
currency = fields.Many2One('currency.currency', 'Currency',
|
|
states={
|
|
'invisible': ~Eval('unit_price_required'),
|
|
@@ -264,6 +271,9 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
unit_price_required = fields.Function(
|
|
fields.Boolean('Unit Price Required'),
|
|
'on_change_with_unit_price_required')
|
|
+ cost_price_required = fields.Function(
|
|
+ fields.Boolean("Cost Price Required"),
|
|
+ 'on_change_with_cost_price_required')
|
|
assignation_required = fields.Function(
|
|
fields.Boolean('Assignation Required'),
|
|
'on_change_with_assignation_required')
|
|
@@ -401,6 +411,13 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
return True
|
|
return False
|
|
|
|
+ @fields.depends('from_location', 'to_location')
|
|
+ def on_change_with_cost_price_required(self, name=None):
|
|
+ from_type = self.from_location.type if self.from_location else None
|
|
+ to_type = self.to_location.type if self.to_location else None
|
|
+ return ((from_type != 'storage' and to_type == 'storage')
|
|
+ or (from_type == 'storage' and to_type != 'storage'))
|
|
+
|
|
@fields.depends('from_location')
|
|
def on_change_with_assignation_required(self, name=None):
|
|
if self.from_location:
|
|
@@ -471,15 +488,13 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
def search_rec_name(cls, name, clause):
|
|
return [('product.rec_name',) + tuple(clause[1:])]
|
|
|
|
- def _compute_product_cost_price(self, direction):
|
|
+ def _compute_product_cost_price(self, direction, product_cost_price=None):
|
|
"""
|
|
Update the cost price on the given product.
|
|
The direction must be "in" if incoming and "out" if outgoing.
|
|
"""
|
|
pool = Pool()
|
|
Uom = pool.get('product.uom')
|
|
- Product = pool.get('product.product')
|
|
- Currency = pool.get('currency.currency')
|
|
|
|
if direction == 'in':
|
|
quantity = self.quantity
|
|
@@ -489,13 +504,7 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
|
|
qty = Decimal(str(qty))
|
|
product_qty = Decimal(str(self.product.quantity))
|
|
- # convert wrt currency
|
|
- 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(self.uom, unit_price,
|
|
- self.product.default_uom)
|
|
+ unit_price = self.get_cost_price(product_cost_price=product_cost_price)
|
|
cost_price = self.product.get_multivalue(
|
|
'cost_price', **self._cost_price_pattern)
|
|
if product_qty + qty > 0 and product_qty >= 0:
|
|
@@ -507,9 +516,7 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
elif direction == 'out':
|
|
new_cost_price = cost_price
|
|
|
|
- digits = Product.cost_price.digits
|
|
- return new_cost_price.quantize(
|
|
- Decimal(str(10.0 ** -digits[1])))
|
|
+ return round_price(new_cost_price)
|
|
|
|
@staticmethod
|
|
def _get_internal_quantity(quantity, uom, product):
|
|
@@ -583,7 +590,7 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
cost_values.append(
|
|
(move.product, cost_price,
|
|
move._cost_price_pattern))
|
|
- if move.cost_price is None:
|
|
+ if move.cost_price_required and move.cost_price is None:
|
|
if cost_price is None:
|
|
cost_price = move.product.get_multivalue(
|
|
'cost_price', **move._cost_price_pattern)
|
|
@@ -609,6 +616,27 @@ class Move(Workflow, ModelSQL, ModelView):
|
|
('company', self.company.id),
|
|
)
|
|
|
|
+ def get_cost_price(self, product_cost_price=None):
|
|
+ "Return the cost price of the move for computation"
|
|
+ pool = Pool()
|
|
+ Currency = pool.get('currency.currency')
|
|
+ UoM = pool.get('product.uom')
|
|
+ with Transaction().set_context(date=self.effective_date):
|
|
+ if (self.from_location.type in {'supplier', 'production'}
|
|
+ or self.to_location.type == 'supplier'):
|
|
+ unit_price = Currency.compute(
|
|
+ self.currency, self.unit_price,
|
|
+ self.company.currency, round=False)
|
|
+ return UoM.compute_price(
|
|
+ self.uom, unit_price, self.product.default_uom)
|
|
+ elif product_cost_price is not None:
|
|
+ return product_cost_price
|
|
+ elif self.cost_price is not None:
|
|
+ return self.cost_price
|
|
+ else:
|
|
+ return self.product.get_multivalue(
|
|
+ 'cost_price', **self._cost_price_pattern)
|
|
+
|
|
@classmethod
|
|
def _cost_price_context(cls, moves):
|
|
pool = Pool()
|