diff --git a/issue4950_sale.diff b/issue4950_sale.diff new file mode 100644 index 0000000..7fc6807 --- /dev/null +++ b/issue4950_sale.diff @@ -0,0 +1,115 @@ +diff -r f9ff7d1399d1 stock.py +--- a/trytond/trytond/modules/sale/stock.py Fri Sep 04 16:30:54 2015 +0200 ++++ b/trytond/trytond/modules/sale/stock.py Fri Sep 04 16:31:35 2015 +0200 +@@ -1,5 +1,6 @@ + #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 itertools import ifilter + from sql.operators import Concat + + from trytond.model import Workflow, ModelView, fields +@@ -60,6 +61,35 @@ + + return super(ShipmentOut, cls).draft(shipments) + ++ def get_origins(self, name): ++ return ', '.join(set(ifilter(None, (m.origin_name ++ for m in self.outgoing_moves)))) ++ ++ @classmethod ++ def _sync_inventory_to_outgoing_grouping_key(cls, move, type): ++ pool = Pool() ++ Move = pool.get('stock.move') ++ key = super(ShipmentOut, ++ cls)._sync_inventory_to_outgoing_grouping_key(move, type) ++ if type == 'outgoing': ++ key = tuple([key, move.origin]) ++ if (type == 'inventory' and move.origin and ++ isinstance(move.origin, Move)): ++ key = tuple([key, move.origin.origin]) ++ return key ++ ++ def _get_outgoing_move(self, move): ++ new_move = super(ShipmentOut, self)._get_outgoing_move(move) ++ if new_move: ++ new_move.origin = move ++ return new_move ++ ++ def _get_inventory_move(self, move): ++ new_move = super(ShipmentOut, self)._get_inventory_move(move) ++ if new_move: ++ new_move.origin = move ++ return new_move ++ + + class ShipmentOutReturn: + __name__ = 'stock.shipment.out.return' +@@ -146,6 +176,7 @@ + @classmethod + def _get_origin(cls): + models = super(Move, cls)._get_origin() ++ models.append('stock.move') + models.append('sale.line') + return models + +diff -r f9ff7d1399d1 tests/scenario_sale.rst +--- a/trytond/trytond/modules/sale/tests/scenario_sale.rst Fri Sep 04 16:30:54 2015 +0200 ++++ b/trytond/trytond/modules/sale/tests/scenario_sale.rst Fri Sep 04 16:31:35 2015 +0200 +@@ -771,3 +771,57 @@ + 5.0 + >>> stock_move.state + u'draft' ++ ++Create a sale with the same products with diferent price to be invoiced on ++shipment and check correctly invoiced:: ++ ++ >>> sale = Sale() ++ >>> sale.party = customer ++ >>> sale.payment_term = payment_term ++ >>> sale.invoice_method = 'shipment' ++ >>> line = sale.lines.new() ++ >>> line.product = product ++ >>> line.quantity = 10.0 ++ >>> line = sale.lines.new() ++ >>> line.product = product ++ >>> line.quantity = 10.0 ++ >>> line.unit_price = Decimal('9.0000') ++ >>> sale.click('quote') ++ >>> sale.click('confirm') ++ >>> sale.click('process') ++ >>> shipment, = sale.shipments ++ >>> config.user = stock_user.id ++ >>> for move in shipment.inventory_moves: ++ ... move.quantity = 5.0 ++ >>> shipment.click('assign_try') ++ True ++ >>> shipment.click('pack') ++ >>> shipment.click('done') ++ >>> config.user = sale_user.id ++ >>> sale.reload() ++ >>> invoice, = sale.invoices ++ >>> _, shipment, = sale.shipments ++ >>> invoice.untaxed_amount ++ Decimal('95.00') ++ >>> first_line, second_line = sorted(invoice.lines, ++ ... key=lambda a: a.unit_price) ++ >>> first_line.unit_price ++ Decimal('9.0000') ++ >>> second_line.unit_price ++ Decimal('10.0000') ++ >>> config.user = stock_user.id ++ >>> shipment.click('assign_try') ++ True ++ >>> shipment.click('pack') ++ >>> shipment.click('done') ++ >>> config.user = sale_user.id ++ >>> sale.reload() ++ >>> _, invoice = sale.invoices ++ >>> invoice.untaxed_amount ++ Decimal('95.00') ++ >>> first_line, second_line = sorted(invoice.lines, ++ ... key=lambda a: a.unit_price) ++ >>> first_line.unit_price ++ Decimal('9.0000') ++ >>> second_line.unit_price ++ Decimal('10.0000') diff --git a/issue4950_stock.diff b/issue4950_stock.diff new file mode 100644 index 0000000..682be26 --- /dev/null +++ b/issue4950_stock.diff @@ -0,0 +1,80 @@ +diff -r 8684df73e037 shipment.py +--- a/trytond/trytond/modules/stock/shipment.py Fri Sep 04 16:29:38 2015 +0200 ++++ b/trytond/trytond/modules/stock/shipment.py Fri Sep 04 16:30:32 2015 +0200 +@@ -1111,6 +1111,14 @@ + unit_price=move.unit_price, + ) + ++ @staticmethod ++ def _sync_inventory_to_outgoing_grouping_key(move, type): ++ ''' ++ Returns the key used to sync inventory and outgoing moves for move ++ Type contains outgoing or incomming to indicate the kind of move ++ ''' ++ return move.product.id ++ + @classmethod + def _sync_inventory_to_outgoing(cls, shipments): + 'Synchronise outgoing moves with inventory moves' +@@ -1125,8 +1133,10 @@ + continue + quantity = Uom.compute_qty(move.uom, move.quantity, + move.product.default_uom, round=False) +- outgoing_qty.setdefault(move.product.id, 0.0) +- outgoing_qty[move.product.id] += quantity ++ key = cls._sync_inventory_to_outgoing_grouping_key(move, ++ 'outgoing') ++ outgoing_qty.setdefault(key, 0.0) ++ outgoing_qty[key] += quantity + + to_create = [] + for move in shipment.inventory_moves: +@@ -1134,19 +1144,20 @@ + continue + qty_default_uom = Uom.compute_qty(move.uom, move.quantity, + move.product.default_uom, round=False) ++ key = cls._sync_inventory_to_outgoing_grouping_key(move, ++ 'inventory') + # Check if the outgoing move doesn't exist already +- if outgoing_qty.get(move.product.id): ++ if outgoing_qty.get(key): + # If it exist, decrease the sum +- if qty_default_uom <= outgoing_qty[move.product.id]: +- outgoing_qty[move.product.id] -= qty_default_uom ++ if qty_default_uom <= outgoing_qty[key]: ++ outgoing_qty[key] -= qty_default_uom + continue + # Else create the complement + else: +- out_quantity = (qty_default_uom +- - outgoing_qty[move.product.id]) ++ out_quantity = (qty_default_uom - outgoing_qty[key]) + out_quantity = Uom.compute_qty( + move.product.default_uom, out_quantity, move.uom) +- outgoing_qty[move.product.id] = 0.0 ++ outgoing_qty[key] = 0.0 + else: + out_quantity = move.quantity + +@@ -1164,16 +1175,18 @@ + for move in shipment.outgoing_moves: + if move.state == 'cancel': + continue +- if outgoing_qty.get(move.product.id, 0.0) > 0.0: ++ key = cls._sync_inventory_to_outgoing_grouping_key(move, ++ 'outgoing') ++ if outgoing_qty.get(key, 0.0) > 0.0: + exc_qty = Uom.compute_qty(move.product.default_uom, +- outgoing_qty[move.product.id], move.uom) ++ outgoing_qty[key], move.uom) + removed_qty = Uom.compute_qty(move.uom, + min(exc_qty, move.quantity), move.product.default_uom, + round=False) + Move.write([move], { + 'quantity': max(0.0, move.quantity - exc_qty), + }) +- outgoing_qty[move.product.id] -= removed_qty ++ outgoing_qty[key] -= removed_qty + + @classmethod + @ModelView.button diff --git a/series b/series index e87ec8e..b5b7225 100644 --- a/series +++ b/series @@ -61,3 +61,5 @@ issue18361002_40001.diff issue24271002_1.diff issue18481003_1.diff issue4766.diff +issue4950_stock.diff +issue4950_sale.diff