changeset a04e65b1a308 in modules/sale_supply:default
details: 
https://hg.tryton.org/modules/sale_supply?cmd=changeset;node=a04e65b1a308
description:
        Fill grouping values when assigning supplied moves

        issue9480
        review296301002
diffstat:

 sale.py  |  69 ++++++++++++++++++++++++++++++++++++++++++++++++---------------
 stock.py |  50 +++++++++++++++++++++++++++++++++------------
 2 files changed, 88 insertions(+), 31 deletions(-)

diffs (180 lines):

diff -r c200371bfea6 -r a04e65b1a308 sale.py
--- a/sale.py   Thu Jul 09 10:21:06 2020 +0100
+++ b/sale.py   Sun Oct 11 16:08:46 2020 +0200
@@ -1,8 +1,9 @@
 # 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 trytond.model import fields
+from trytond.model import Model, fields
 from trytond.pool import Pool, PoolMeta
 from trytond.pyson import Eval
+from trytond.transaction import Transaction
 
 
 class Sale(metaclass=PoolMeta):
@@ -169,7 +170,7 @@
             origin=self.sale,
             )
 
-    def assign_supplied(self, location_quantities):
+    def assign_supplied(self, quantities, grouping=('product',)):
         '''
         Assign supplied move
 
@@ -182,20 +183,50 @@
 
         if self.supply_state != 'supplied':
             return
+
+        def get_key(move, location_id):
+            key = (location_id,)
+            for field in grouping:
+                value = getattr(move, field)
+                if isinstance(value, Model):
+                    value = value.id
+                key += (value,)
+            return key
+
+        def get_values(key, location_name):
+            yield location_name, key[0]
+            for field, value in zip(grouping, key[1:]):
+                if value is not None and '.' not in field:
+                    yield field, value
+
+        def match(key, pattern):
+            for k, p in zip(key, pattern):
+                if p is None or k == p:
+                    continue
+                else:
+                    return False
+            else:
+                return True
+
         moves = set()
         for move in self.moves:
             for inv_move in move.shipment.inventory_moves:
                 if inv_move.product.id == self.product.id:
                     moves.add(inv_move)
+        to_write = []
+        to_assign = []
         for move in moves:
             if move.state != 'draft':
                 continue
-            location_qties_converted = {}
-            for location_id, quantity in location_quantities.items():
-                location_qties_converted[location_id] = (
-                    Uom.compute_qty(move.product.default_uom,
-                        quantity, move.uom, round=False))
-            to_pick = move.pick_product(location_qties_converted)
+            qties_converted = []
+            for key, quantity in quantities.items():
+                move_key = get_key(move, key[0])
+                if match(key, move_key):
+                    qty = Uom.compute_qty(
+                        move.product.default_uom, quantity, move.uom,
+                        round=False)
+                    qties_converted.append((key, qty))
+            to_pick = move.pick_product(qties_converted)
 
             picked_qties = sum(qty for _, qty in to_pick)
             if picked_qties < move.quantity:
@@ -205,18 +236,22 @@
                         })
             else:
                 first = True
-            for from_location, qty in to_pick:
-                values = {
-                    'from_location': from_location.id,
-                    'quantity': qty,
-                    }
+            for key, qty in to_pick:
+                values = dict(get_values(key, 'from_location'))
+                values['quantity'] = move.uom.round(qty)
                 if first:
-                    Move.write([move], values)
-                    Move.assign([move])
+                    to_write.extend([[move], values])
+                    to_assign.append(move)
+                    first = False
                 else:
-                    Move.assign(Move.copy([move], default=values))
+                    with Transaction().set_context(_stock_move_split=True):
+                        to_assign.extend(Move.copy([move], default=values))
 
                 qty_default_uom = Uom.compute_qty(move.uom, qty,
                     move.product.default_uom, round=False)
 
-                location_quantities[from_location] -= qty_default_uom
+                quantities[key] -= qty_default_uom
+        if to_write:
+            Move.write(*to_write)
+        if to_assign:
+            Move.assign(to_assign)
diff -r c200371bfea6 -r a04e65b1a308 stock.py
--- a/stock.py  Thu Jul 09 10:21:06 2020 +0100
+++ b/stock.py  Sun Oct 11 16:08:46 2020 +0200
@@ -2,7 +2,7 @@
 # this repository contains the full copyright notices and license terms.
 from collections import defaultdict
 
-from trytond.model import ModelView, Workflow
+from trytond.model import Model, ModelView, Workflow
 from trytond.pool import Pool, PoolMeta
 
 
@@ -13,20 +13,42 @@
     @ModelView.button
     @Workflow.transition('done')
     def done(cls, shipments):
-        SaleLine = Pool().get('sale.line')
-
         super(ShipmentIn, cls).done(shipments)
 
         # Assigned sale move lines
         for shipment in shipments:
-            move_ids = [x.id for x in shipment.incoming_moves]
-            sale_lines = SaleLine.search([
-                    ('purchase_request.purchase_line.moves',
-                        'in', move_ids),
-                    ('purchase_request.origin', 'like', 'sale.sale,%'),
-                    ])
-            pbl = defaultdict(lambda: defaultdict(int))
-            for move in shipment.inventory_moves:
-                pbl[move.product][move.to_location] += move.internal_quantity
-            for sale_line in sale_lines:
-                sale_line.assign_supplied(pbl[sale_line.product])
+            shipment.assign_supplied()
+
+    def assign_supplied(self, grouping=('product',), filter_=None):
+        pool = Pool()
+        SaleLine = pool.get('sale.line')
+
+        def filter_func(move):
+            if filter_ is None:
+                return True
+            for fieldname, values in filter_:
+                value = getattr(move, fieldname)
+                if isinstance(value, Model):
+                    value = value.id
+                if value not in values:
+                    return False
+
+        def get_key(move):
+            key = (move.to_location.id,)
+            for field in grouping:
+                value = getattr(move, field)
+                if isinstance(value, Model):
+                    value = value.id
+                key += (value,)
+            return key
+        move_ids = [m.id for m in filter(filter_func, self.incoming_moves)]
+        sale_lines = SaleLine.search([
+                ('purchase_request.purchase_line.moves', 'in', move_ids),
+                ('purchase_request.origin', 'like', 'sale.sale,%'),
+                ])
+        pbl = defaultdict(lambda: defaultdict(int))
+        for move in filter(filter_func, self.inventory_moves):
+            pbl[move.product][get_key(move)] += move.internal_quantity
+        for sale_line in sale_lines:
+            sale_line.assign_supplied(
+                pbl[sale_line.product], grouping=grouping)

Reply via email to