diff --git a/modules/sale_supply_drop_shipment/CHANGELOG b/modules/sale_supply_drop_shipment/CHANGELOG index 002c18f450..4843ef59ee 100644 --- a/modules/sale_supply_drop_shipment/CHANGELOG +++ b/modules/sale_supply_drop_shipment/CHANGELOG @@ -1,3 +1,4 @@ +* Support splitting drop shipment * Split customer moves when splitting supplier moves * Rename 'done' button to 'do' diff --git a/modules/sale_supply_drop_shipment/__init__.py b/modules/sale_supply_drop_shipment/__init__.py index ac66c3782f..f5eea42949 100644 --- a/modules/sale_supply_drop_shipment/__init__.py +++ b/modules/sale_supply_drop_shipment/__init__.py @@ -31,6 +31,11 @@ def register(): party.Erase, module='sale_supply_drop_shipment', type_='wizard') Pool.register( + stock.ShipmentDropSplit, stock.MoveSplit, module='sale_supply_drop_shipment', type_='model', depends=['stock_split']) + Pool.register( + stock.SplitShipment, + module='sale_supply_drop_shipment', type_='wizard', + depends=['stock_split']) diff --git a/modules/sale_supply_drop_shipment/stock.py b/modules/sale_supply_drop_shipment/stock.py index c19d46cbcd..6b844477e2 100644 --- a/modules/sale_supply_drop_shipment/stock.py +++ b/modules/sale_supply_drop_shipment/stock.py @@ -535,6 +535,47 @@ class ShipmentDrop( return self.customer_moves +class ShipmentDropSplit(metaclass=PoolMeta): + __name__ = 'stock.shipment.drop' + + @classmethod + def __setup__(cls): + super().__setup__() + cls._buttons.update({ + 'split_wizard': { + 'readonly': Eval('state') != 'draft', + 'invisible': Eval('state') != 'draft', + 'depends': ['state'], + }, + }) + + @classmethod + @ModelView.button_action('stock_split.wizard_split_shipment') + def split_wizard(cls, shipments): + pass + + +class SplitShipment(metaclass=PoolMeta): + __name__ = 'stock.shipment.split' + + def get_moves(self, shipment): + moves = super().get_moves(shipment) + if shipment.__name__ == 'stock.shipment.drop': + moves = shipment.supplier_moves + return moves + + def transition_split(self): + shipment = self.record + if shipment.__name__ == 'stock.shipment.drop': + customer_moves = [] + for move in self.start.moves: + customer_moves.extend(move.moves_drop) + self.start.moves = [*self.start.moves, *customer_moves] + self.start.domain_moves = [ + *self.start.domain_moves, *customer_moves] + return super().transition_split() + + class Move(metaclass=PoolMeta): __name__ = 'stock.move' diff --git a/modules/sale_supply_drop_shipment/stock.xml b/modules/sale_supply_drop_shipment/stock.xml index 6eae621e83..dfe26dce03 100644 --- a/modules/sale_supply_drop_shipment/stock.xml +++ b/modules/sale_supply_drop_shipment/stock.xml @@ -264,6 +264,20 @@ this repository contains the full copyright notices and license terms. --> + + + stock.shipment.drop + + shipment_drop_split_form + + + + stock.shipment.drop + split_wizard + Split + + + diff --git a/modules/sale_supply_drop_shipment/tests/scenario_sale_supply_drop_shipment_split.rst b/modules/sale_supply_drop_shipment/tests/scenario_sale_supply_drop_shipment_split.rst new file mode 100644 index 0000000000..bd8b83b8b8 --- /dev/null +++ b/modules/sale_supply_drop_shipment/tests/scenario_sale_supply_drop_shipment_split.rst @@ -0,0 +1,140 @@ +======================================== +Sale Supply Drop Shipment Split Scenario +======================================== + +Imports:: + + >>> from decimal import Decimal + + >>> from proteus import Model, Wizard + >>> from trytond.modules.account.tests.tools import create_chart, get_accounts + >>> from trytond.modules.company.tests.tools import create_company + >>> from trytond.tests.tools import activate_modules, assertEqual + +Activate modules:: + + >>> config = activate_modules([ + ... 'sale_supply_drop_shipment', + ... 'stock_split', + ... ]) + + >>> Move = Model.get('stock.move') + >>> Party = Model.get('party.party') + >>> ProductCategory = Model.get('product.category') + >>> ProductSupplier = Model.get('purchase.product_supplier') + >>> ProductTemplate = Model.get('product.template') + >>> ProductUom = Model.get('product.uom') + >>> Purchase = Model.get('purchase.purchase') + >>> PurchaseRequest = Model.get('purchase.request') + >>> Sale = Model.get('sale.sale') + >>> Shipment = Model.get('stock.shipment.drop') + +Create company:: + + >>> _ = create_company() + +Create chart of account:: + + >>> _ = create_chart() + >>> accounts = get_accounts() + +Create parties:: + + >>> supplier = Party(name="Supplier") + >>> supplier.save() + >>> customer = Party(name="Customer") + >>> customer.save() + +Create account category:: + + >>> account_category = ProductCategory(name="Account Category") + >>> account_category.accounting = True + >>> account_category.account_expense = accounts['expense'] + >>> account_category.account_revenue = accounts['revenue'] + >>> account_category.save() + +Create product:: + + >>> unit, = ProductUom.find([('name', '=', "Unit")]) + + >>> template = ProductTemplate() + >>> template.name = "Product" + >>> template.default_uom = unit + >>> template.type = 'goods' + >>> template.purchasable = True + >>> template.salable = True + >>> template.list_price = Decimal('10.000') + >>> template.supply_on_sale = 'always' + >>> template.account_category = account_category + >>> product_supplier = template.product_suppliers.new() + >>> product_supplier.party = supplier + >>> product_supplier.drop_shipment = True + >>> template.save() + >>> product, = template.products + >>> product_supplier.save() + +Sale 5 products:: + + >>> sale = Sale(party=customer) + >>> line = sale.lines.new() + >>> line.product = product + >>> line.quantity = 5 + >>> sale.click('quote') + >>> sale.click('confirm') + >>> sale.state + 'processing' + +Create purchase request:: + + >>> purchase_request, = PurchaseRequest.find() + >>> create_purchase = Wizard( + ... 'purchase.request.create_purchase', [purchase_request]) + >>> purchase, = Purchase.find() + >>> purchase.click('quote') + >>> purchase.click('confirm') + >>> purchase.state + 'processing' + +Split supplier move of drop shipment:: + + >>> shipment, = Shipment.find() + >>> move, = shipment.supplier_moves + >>> split = move.click('split_wizard') + >>> split.form.quantity = 2 + >>> split.form.count = 1 + >>> split.execute('split') + + >>> shipment.reload() + >>> len(shipment.supplier_moves) + 2 + >>> len(shipment.customer_moves) + 2 + >>> for move in shipment.supplier_moves: + ... assertEqual(move.quantity, sum(m.quantity for m in move.moves_drop)) + +Split drop shipment:: + + >>> shipment.click('draft') + >>> split = shipment.click('split_wizard') + >>> split.form.moves.append(Move(shipment.supplier_moves[0].id)) + >>> split.execute('split') + + >>> shipment2, = Shipment.find([('id', '!=', shipment.id)]) + + >>> Shipment.click([shipment, shipment2], 'wait') + + >>> len(shipment.supplier_moves) + 1 + >>> len(shipment.customer_moves) + 1 + >>> assertEqual( + ... sum(m.quantity for m in shipment.supplier_moves), + ... sum(m.quantity for m in shipment.customer_moves)) + + >>> len(shipment2.supplier_moves) + 1 + >>> len(shipment2.customer_moves) + 1 + >>> assertEqual( + ... sum(m.quantity for m in shipment2.supplier_moves), + ... sum(m.quantity for m in shipment2.customer_moves)) diff --git a/modules/sale_supply_drop_shipment/view/shipment_drop_split_form.xml b/modules/sale_supply_drop_shipment/view/shipment_drop_split_form.xml new file mode 100644 index 0000000000..be65c958f3 --- /dev/null +++ b/modules/sale_supply_drop_shipment/view/shipment_drop_split_form.xml @@ -0,0 +1,8 @@ + + + + +