changeset b595cff162c5 in modules/product_cost_fifo:default
details: 
https://hg.tryton.org/modules/product_cost_fifo?cmd=changeset;node=b595cff162c5
description:
        Improve selection of moves used for cost

        issue8700
        review282201004
diffstat:

 move.py    |  34 +++++++++++++++++++++++-
 product.py |  84 +++++++++++++++++++++++++++++++------------------------------
 setup.py   |   2 +-
 3 files changed, 76 insertions(+), 44 deletions(-)

diffs (181 lines):

diff -r 4d1ec7e59853 -r b595cff162c5 move.py
--- a/move.py   Fri Oct 11 11:44:56 2019 +0200
+++ b/move.py   Mon Oct 14 00:04:14 2019 +0200
@@ -2,6 +2,8 @@
 # this repository contains the full copyright notices and license terms.
 from decimal import Decimal
 
+from sql import operators, Literal
+
 from trytond.i18n import gettext
 from trytond.model import Workflow, ModelView, fields, Check
 from trytond.model.exceptions import AccessError
@@ -13,7 +15,13 @@
 
 class Move(metaclass=PoolMeta):
     __name__ = 'stock.move'
-    fifo_quantity = fields.Float('FIFO Quantity')
+    fifo_quantity = fields.Float(
+        'FIFO Quantity',
+        help="Quantity used by FIFO.")
+    fifo_quantity_available = fields.Function(fields.Float(
+            "FIFO Quantity Available",
+            help="Quantity available for FIFO"),
+        'get_fifo_quantity_available')
 
     @classmethod
     def __setup__(cls):
@@ -31,6 +39,27 @@
     def default_fifo_quantity():
         return 0.0
 
+    def get_fifo_quantity_available(self, name):
+        return self.quantity - (self.fifo_quantity or 0)
+
+    @classmethod
+    def domain_fifo_quantity_available(cls, domain, tables):
+        table, _ = tables[None]
+        name, operator, value = domain
+        field = cls.fifo_quantity_available._field
+        Operator = fields.SQL_OPERATORS[operator]
+        column = (
+            cls.quantity.sql_column(table)
+            - cls.fifo_quantity.sql_column(table))
+        expression = Operator(column, field._domain_value(operator, value))
+        if isinstance(expression, operators.In) and not expression.right:
+            expression = Literal(False)
+        elif isinstance(expression, operators.NotIn) and not expression.right:
+            expression = Literal(True)
+        expression = field._domain_add_null(
+            column, operator, value, expression)
+        return expression
+
     def _update_fifo_out_product_cost_price(self):
         '''
         Update the product cost price of the given product on the move. Update
@@ -44,7 +73,8 @@
         total_qty = Uom.compute_qty(self.uom, self.quantity,
             self.product.default_uom, round=False)
 
-        fifo_moves = self.product.get_fifo_move(total_qty)
+        with Transaction().set_context(company=self.company.id):
+            fifo_moves = self.product.get_fifo_move(total_qty)
 
         cost_price = Decimal("0.0")
         consumed_qty = 0.0
diff -r 4d1ec7e59853 -r b595cff162c5 product.py
--- a/product.py        Fri Oct 11 11:44:56 2019 +0200
+++ b/product.py        Mon Oct 14 00:04:14 2019 +0200
@@ -21,6 +21,33 @@
 class Product(metaclass=PoolMeta):
     __name__ = 'product.product'
 
+    def _get_available_fifo_moves(self):
+        pool = Pool()
+        Move = pool.get('stock.move')
+        return Move.search([
+                ('product', '=', self.id),
+                ('state', '=', 'done'),
+                self._domain_moves_cost,
+                ('fifo_quantity_available', '>', 0),
+                ('to_location.type', '=', 'storage'),
+                ('from_location.type', 'in', ['supplier', 'production']),
+                ('to_location.type', '=', 'storage'),
+                ], order=[('effective_date', 'DESC'), ('id', 'DESC')])
+
+    def _get_fifo_quantity(self):
+        pool = Pool()
+        Location = pool.get('stock.location')
+
+        locations = Location.search([
+            ('type', '=', 'storage'),
+            ])
+        stock_date_end = datetime.date.today()
+        location_ids = [l.id for l in locations]
+        with Transaction().set_context(
+                locations=location_ids,
+                stock_date_end=stock_date_end):
+            return self.__class__(self.id).quantity
+
     def get_fifo_move(self, quantity=0.0):
         '''
         Return a list of (move, qty) where move is the move to be
@@ -29,50 +56,25 @@
         moves for the given quantity.
         '''
         pool = Pool()
-        Move = pool.get('stock.move')
         Uom = pool.get('product.uom')
-        Location = pool.get('stock.location')
-
-        locations = Location.search([
-            ('type', '=', 'storage'),
-            ])
-        stock_date_end = datetime.date.today()
-        location_ids = [l.id for l in locations]
-        with Transaction().set_context(locations=location_ids,
-                stock_date_end=stock_date_end):
-            product = self.__class__(self.id)
-        offset = 0
-        limit = Transaction().database.IN_MAX
-        avail_qty = product.quantity
-        fifo_moves = []
 
-        while avail_qty > 0.0:
-            moves = Move.search([
-                ('product', '=', product.id),
-                ('state', '=', 'done'),
-                ('from_location.type', 'in', ['supplier', 'production']),
-                ('to_location.type', '=', 'storage'),
-                ], offset=offset, limit=limit,
-                order=[('effective_date', 'DESC'), ('id', 'DESC')])
-            if not moves:
-                break
-            offset += limit
+        avail_qty = self._get_fifo_quantity()
+        fifo_moves = []
+        moves = self._get_available_fifo_moves()
+        for move in moves:
+            qty = Uom.compute_qty(move.uom,
+                    move.fifo_quantity_available,
+                    self.default_uom, round=False)
+            avail_qty -= qty
 
-            for move in moves:
-                qty = Uom.compute_qty(move.uom,
-                        move.quantity - move.fifo_quantity,
-                        product.default_uom, round=False)
-                avail_qty -= qty
-
-                if avail_qty <= quantity:
-                    if avail_qty > 0.0:
-                        fifo_moves.append(
-                            (move, min(qty, quantity - avail_qty)))
-                    else:
-                        fifo_moves.append(
-                            (move, min(quantity, qty + avail_qty)))
-                        break
-
+            if avail_qty <= quantity:
+                if avail_qty > 0.0:
+                    fifo_moves.append(
+                        (move, min(qty, quantity - avail_qty)))
+                else:
+                    fifo_moves.append(
+                        (move, min(quantity, qty + avail_qty)))
+                    break
         fifo_moves.reverse()
         return fifo_moves
 
diff -r 4d1ec7e59853 -r b595cff162c5 setup.py
--- a/setup.py  Fri Oct 11 11:44:56 2019 +0200
+++ b/setup.py  Mon Oct 14 00:04:14 2019 +0200
@@ -45,7 +45,7 @@
         'hg+http://hg.tryton.org/modules/%s#egg=%s-%s' % (
             name[8:], name, version))
 
-requires = []
+requires = ['python-sql']
 for dep in info.get('depends', []):
     if not re.match(r'(ir|res)(\W|$)', dep):
         requires.append(get_require_version('trytond_%s' % dep))

Reply via email to