diff --git a/bt5/erp5_mrp/PathTemplateItem/portal_deliveries/production_report_builder/category_movement_group_on_line.xml b/bt5/erp5_mrp/PathTemplateItem/portal_deliveries/production_report_builder/category_movement_group_on_line.xml index c24f856c12d01ad05a9e10198299c4edda20482a..b93a0c414c09866c7106d2fd5727c6d2cb804049 100644 --- a/bt5/erp5_mrp/PathTemplateItem/portal_deliveries/production_report_builder/category_movement_group_on_line.xml +++ b/bt5/erp5_mrp/PathTemplateItem/portal_deliveries/production_report_builder/category_movement_group_on_line.xml @@ -42,6 +42,7 @@ <string>base_application</string> <string>industrial_phase</string> <string>quantity_unit</string> + <string>aggregate</string> </tuple> </value> </item> diff --git a/product/ERP5/Document/TransformationSimulationRule.py b/product/ERP5/Document/TransformationSimulationRule.py index 56badac7e6e44bb4a8bf0ad851b9018a96051f25..98cad7371aa539dbca21a584f216b765f82ac3ed 100644 --- a/product/ERP5/Document/TransformationSimulationRule.py +++ b/product/ERP5/Document/TransformationSimulationRule.py @@ -134,6 +134,8 @@ class TransformationRuleMovementGenerator(MovementGeneratorMixin): amount.getCategoryList(), base=True) movement.quantity = - movement.quantity + # aggregation of items should not be propagated to what comes from transformation + movement.setAggregateList([]) yield movement phase_dict = parent_movement.asComposedDocument() \ .getPreviousTradePhaseDict(phase_set) diff --git a/product/ERP5/tests/testBPMCore.py b/product/ERP5/tests/testBPMCore.py index e5c8176f0369e41520fd3a52fcc617187c8a4140..963fe5bde92762dc64274a2a1f69d7a2ef122041 100644 --- a/product/ERP5/tests/testBPMCore.py +++ b/product/ERP5/tests/testBPMCore.py @@ -39,7 +39,7 @@ class TestBPMMixin(ERP5TypeTestCase): """Skeletons for tests which depend on BPM""" def getBusinessTemplateList(self): - return ('erp5_base', 'erp5_pdm', 'erp5_simulation', 'erp5_trade', + return ('erp5_base', 'erp5_pdm', 'erp5_simulation', 'erp5_trade', 'erp5_item', 'erp5_accounting', 'erp5_invoicing', 'erp5_simplified_invoicing', 'erp5_core_proxy_field_legacy', 'erp5_configurator_standard_solver', diff --git a/product/ERP5/tests/testMRP.py b/product/ERP5/tests/testMRP.py index 4fa4d406daf2ab47ea32497dc9d3b4413d847f0e..3434804cb752b3611adc58bce1142487a03d2e11 100644 --- a/product/ERP5/tests/testMRP.py +++ b/product/ERP5/tests/testMRP.py @@ -133,31 +133,40 @@ class TestMRPMixin(TestBPMMixin): def createDefaultTransformation(self): resource = lambda: self.createProduct(quantity_unit_list=['weight/kg']) - transformation = self.createTransformation(resource_value=resource()) + self.produced_resource = resource() + transformation = self.createTransformation(resource_value=self.produced_resource) + self.consumed_resource_1 = resource() self.createTransformedResource(transformation=transformation, - resource_value=resource(), + resource_value=self.consumed_resource_1, quantity=3, quantity_unit_list=['weight/kg'], trade_phase='mrp/p0') + self.consumed_resource_2 = resource() self.createTransformedResource(transformation=transformation, - resource_value=resource(), + resource_value=self.consumed_resource_2, quantity=1, quantity_unit_list=['weight/kg'], trade_phase='mrp/p0') + self.consumed_resource_3 = resource() self.createTransformedResource(transformation=transformation, - resource_value=resource(), + resource_value=self.consumed_resource_3, quantity=4, quantity_unit_list=['weight/kg'], trade_phase='mrp/p1') + self.consumed_resource_4 = resource() self.createTransformedResource(transformation=transformation, - resource_value=resource(), + resource_value=self.consumed_resource_4, quantity=1, quantity_unit_list=['weight/kg'], trade_phase='mrp/p1') return transformation def createBusinessProcess1(self, node_p0=None): - """ order p0 s0 p1 deliver + """ + PPL : Production Packing List + PR : Production Report + PO : Production Order + order p0 s0 p1 deliver ------- S0 ---- S1 ---- S2 ---- S3 ------- S4 PO PR PPL PR PPL """ @@ -207,18 +216,23 @@ class TestMRPMixin(TestBPMMixin): class TestMRPImplementation(TestMRPMixin): """the test for implementation""" - def test(self): - workshop = self.createNode(title='workshop') - workshop2 = self.createNode(title='workshop2') - destination = self.createNode(title='destination') - business_process = self.createBusinessProcess1(workshop2) - order = self.createDefaultOrder(business_process) - order_line, = order.objectValues() - order._edit(source_value=workshop, destination_value=destination) + def createMRPOrder(self, use_item=False): + self.workshop = self.createNode(title='workshop') + self.workshop2 = self.createNode(title='workshop2') + self.destination = self.createNode(title='destination') + business_process = self.createBusinessProcess1(self.workshop2) + self.order = self.createDefaultOrder(business_process) + self.order_line, = self.order.objectValues() + if use_item: + self.item = self.portal.item_module.newContent() + self.order_line.setAggregateValue(self.item) + self.order._edit(source_value=self.workshop, destination_value=self.destination) + self.order.plan() self.tic() - order.plan() - self.tic() + def testSimpleOrder(self): + self.createMRPOrder() + order = self.order ar, = order.getCausalityRelatedValueList(portal_type="Applied Rule") sm, = ar.objectValues() # order @@ -227,7 +241,7 @@ class TestMRPImplementation(TestMRPMixin): ar, = sm.objectValues() movement_list = [] - resource = order_line.getResource() + resource = self.order_line.getResource() for sm in ar.objectValues(): self.assertEqual(sm.getSource(), None) self.assertTrue(sm.getDestination()) @@ -266,14 +280,14 @@ class TestMRPImplementation(TestMRPMixin): order.localBuild() self.tic() variation = 'industrial_phase/trade_phase/mrp/p0' - self.checkStock(resource, (workshop2, variation, 10)) + self.checkStock(resource, (self.workshop2, variation, 10)) ppl1, = getRelatedDeliveryList("Production Packing List") ppl1.start() ppl1.deliver() order.localBuild() self.tic() - self.checkStock(resource, (workshop, variation, 10)) + self.checkStock(resource, (self.workshop, variation, 10)) pr2, = (x for x in getRelatedDeliveryList("Production Report") if x.aq_base is not pr1.aq_base) @@ -281,15 +295,44 @@ class TestMRPImplementation(TestMRPMixin): pr2.deliver() order.localBuild() self.tic() - self.checkStock(resource, (workshop, '', 10)) + self.checkStock(resource, (self.workshop, '', 10)) ppl2, = (x for x in getRelatedDeliveryList("Production Packing List") if x.aq_base is not ppl1.aq_base) ppl2.start() ppl2.deliver() self.tic() - self.checkStock(resource, (destination, '', 10)) + self.checkStock(resource, (self.destination, '', 10)) + + def checkExpectedLineList(self, delivery, expected_line_list): + found_line_list = [] + for line in delivery.getMovementList(): + found_line_list.append((line.getResourceValue(), line.getQuantity(), + line.getAggregateValue())) + found_line_list.sort() + expected_line_list.sort() + self.assertEqual(expected_line_list, found_line_list) + + def testOrderWithItem(self): + """ + Check item propagation from Production Order to Production Report + and Production Packing List + """ + self.createMRPOrder(use_item=True) + order = self.order + order.confirm() + order.localBuild() + order_line = self.order_line + resource = order_line.getResourceValue() + self.tic() + production_report, = order.getCausalityRelatedValueList( + portal_type="Production Report") + # resource, quantity, item + expected_line_list = [(self.produced_resource, 10.0, self.item), + (self.consumed_resource_1, -30.0, None), + (self.consumed_resource_2, -10.0, None)] + self.checkExpectedLineList(production_report, expected_line_list) def test_suite(): suite = unittest.TestSuite()