diff --git a/modules/purchase_trade/party.py b/modules/purchase_trade/party.py index b4cb2a2..ba0dddb 100755 --- a/modules/purchase_trade/party.py +++ b/modules/purchase_trade/party.py @@ -141,11 +141,12 @@ class Party(metaclass=PoolMeta): def get_sla_cost(self,location): if self.sla: - for sla in self.sla: - SlaPlace = Pool().get('party.execution.place') - sp = SlaPlace.search([('pes','=', sla.id),('location','=',location)]) - if sp: - return sp[0].cost,sp[0].mode,sp[0].currency,sp[0].unit + for sla in self.sla: + SlaPlace = Pool().get('party.execution.place') + sp = SlaPlace.search([('pes','=', sla.id),('location','=',location)]) + if sp: + return sp[0].cost,sp[0].mode,sp[0].currency,sp[0].unit + return None, None, None, None def get_alf(self): if self.name == 'CARGO CONTROL': diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py index 0a9253c..2a4c259 100755 --- a/modules/purchase_trade/stock.py +++ b/modules/purchase_trade/stock.py @@ -799,23 +799,30 @@ class ShipmentIn(metaclass=PoolMeta): else: return str(self.id) - def create_fee(self,controller): - Fee = Pool().get('fee.fee') - Product = Pool().get('product.product') - fee = Fee() - fee.shipment_in = self.id - fee.supplier = controller - fee.type = 'budgeted' - fee.p_r = 'pay' - price,mode,curr,unit = controller.get_sla_cost(self.to_location) - if price and mode and curr and unit: - fee.mode = mode - fee.currency = curr - fee.unit = unit - fee.quantity = self.get_bales() or 1 - fee.product = Product.get_by_name('Reweighing') - fee.price = price - Fee.save([fee]) + def create_fee(self,controller): + Fee = Pool().get('fee.fee') + Product = Pool().get('product.product') + if not controller: + logger.info("CREATE_FEE_SKIPPED:NO_CONTROLLER shipment=%s", self) + return + fee = Fee() + fee.shipment_in = self.id + fee.supplier = controller + fee.type = 'budgeted' + fee.p_r = 'pay' + price,mode,curr,unit = controller.get_sla_cost(self.to_location) + if not (price and mode and curr and unit): + logger.info( + "CREATE_FEE_SKIPPED:NO_SLA shipment=%s controller=%s location=%s", + self, controller, self.to_location) + return + fee.mode = mode + fee.currency = curr + fee.unit = unit + fee.quantity = self.get_bales() or 1 + fee.product = Product.get_by_name('Reweighing') + fee.price = price + Fee.save([fee]) def get_controller(self): ControllerCategory = Pool().get('party.category') diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index 91bf0a3..f9d7f89 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -269,6 +269,40 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual(line._get_linked_unit_factor(), Decimal('2')) + def test_get_sla_cost_returns_empty_tuple_when_no_place_matches(self): + 'controller sla helper keeps a stable tuple contract when no sla rule matches' + Party = Pool().get('party.party') + party = Party() + party.sla = [] + + self.assertEqual( + party.get_sla_cost(Mock()), + (None, None, None, None)) + + def test_create_fee_skips_when_controller_has_no_sla_cost(self): + 'shipment fee creation skips cleanly when controller has no matching sla' + ShipmentIn = Pool().get('stock.shipment.in') + shipment = ShipmentIn() + shipment.id = 99 + shipment.to_location = Mock() + shipment.get_bales = Mock(return_value=Decimal('10')) + controller = Mock() + controller.get_sla_cost.return_value = (None, None, None, None) + + fee_model = Mock() + product_model = Mock() + + with patch('trytond.modules.purchase_trade.stock.Pool') as PoolMock: + PoolMock.return_value.get.side_effect = lambda name: { + 'fee.fee': fee_model, + 'product.product': product_model, + }[name] + + shipment.create_fee(controller) + + fee_model.save.assert_not_called() + product_model.get_by_name.assert_not_called() + def test_purchase_line_default_pricing_rule_comes_from_configuration(self): 'purchase line pricing_rule defaults to the purchase_trade singleton value' PurchaseLine = Pool().get('purchase.line')