diff --git a/combo/apps/lingo/models.py b/combo/apps/lingo/models.py index c8f150a6..8784420c 100644 --- a/combo/apps/lingo/models.py +++ b/combo/apps/lingo/models.py @@ -638,13 +638,16 @@ class BasketItem(models.Model): ordering = ['regie', 'extra_fee', 'subject'] @classmethod - def get_items_to_be_paid(cls, user): + def get_items_to_be_paid(cls, user, poll=False, raise_on_poll=False): qs = cls.objects.filter( user=user, payment_date__isnull=True, waiting_date__isnull=True, cancellation_date__isnull=True ) - for transaction in Transaction.objects.filter(items__in=qs): - if transaction.can_poll_backend(): - transaction.poll_backend() + if poll: + for transaction in Transaction.objects.filter(items__in=qs): + if transaction.can_poll_backend(): + if raise_on_poll: + raise NothingInCacheException + transaction.poll_backend() return qs def notify(self, status): @@ -1087,7 +1090,9 @@ class LingoBasketCell(CellBase): def render(self, context): basket_template = template.loader.get_template('lingo/combo/basket.html') - items = BasketItem.get_items_to_be_paid(context['request'].user) + items = BasketItem.get_items_to_be_paid( + context['request'].user, poll=True, raise_on_poll=not context.get('synchronous') + ) regies = {} for item in items: if not item.regie_id in regies: @@ -1112,7 +1117,7 @@ class LingoRecentTransactionsCell(CellBase): def is_enabled(cls): return Regie.objects.exists() - def get_transactions_queryset(self, context): + def get_transactions_queryset(self, context, poll=False): user = context['request'].user # list transactions : # * paid by the user @@ -1120,9 +1125,12 @@ class LingoRecentTransactionsCell(CellBase): qs = Transaction.objects.filter(models.Q(user=user) | models.Q(items__user=user)).filter( start_date__gte=timezone.now() - datetime.timedelta(days=7) ) - for transaction in qs: - if transaction.can_poll_backend() and transaction.is_running(): - transaction.poll_backend() + if poll: + for transaction in qs: + if transaction.can_poll_backend() and transaction.is_running(): + if not context.get('synchronous'): + raise NothingInCacheException + transaction.poll_backend() return qs def is_relevant(self, context): @@ -1132,7 +1140,9 @@ class LingoRecentTransactionsCell(CellBase): def render(self, context): recent_transactions_template = template.loader.get_template('lingo/combo/recent_transactions.html') - context['transactions'] = self.get_transactions_queryset(context).distinct().order_by('-start_date') + context['transactions'] = ( + self.get_transactions_queryset(context, poll=True).distinct().order_by('-start_date') + ) return recent_transactions_template.render(context) diff --git a/tests/conftest.py b/tests/conftest.py index c2abf8cf..4d413683 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -70,4 +70,14 @@ def nocache(settings): @pytest.fixture def synchronous_cells(settings): - settings.COMBO_TEST_ALWAYS_RENDER_CELLS_SYNCHRONOUSLY = True + class M: + @staticmethod + def on(): + settings.COMBO_TEST_ALWAYS_RENDER_CELLS_SYNCHRONOUSLY = True + + @staticmethod + def off(): + settings.COMBO_TEST_ALWAYS_RENDER_CELLS_SYNCHRONOUSLY = False + + M.on() + return M diff --git a/tests/test_lingo_payment.py b/tests/test_lingo_payment.py index a03aede0..46aa6c67 100644 --- a/tests/test_lingo_payment.py +++ b/tests/test_lingo_payment.py @@ -2153,6 +2153,8 @@ class TestPolling: self, payment_status, app, + user, + synchronous_cells, ): # Try to pay pay_resp = app.get('/test_basket_cell/') @@ -2171,15 +2173,40 @@ class TestPolling: order_id=transaction.order_id, ) - # Try to pay again + # check get_items_to_be_paid() does not poll anymore + BasketItem.get_items_to_be_paid(user) + assert payment_status.call_count == 0 + + # Try to pay again, only with current information + synchronous_cells.off() resp = app.get('/test_basket_cell/') - assert 'foo item' not in resp - assert 'Pay' not in resp - assert 'Running' in resp + assert 'Loading' in resp.pyquery('.lingo-basket-cell').text() + assert 'Loading' in resp.pyquery('.lingo-recent-transactions-cell').text() resp = pay_resp.click('Pay').follow() assert 'Some items are already paid or' in resp - assert 'foo item' not in resp - assert 'Running' in resp + assert len(resp.pyquery('.lingo-basket-cell')) == 0 + assert 'Loading' in resp.pyquery('.lingo-recent-transactions-cell').text() + assert payment_status.call_count == 1 # pay made a call to payfip backend + payment_status.reset_mock() + + # Make rendering synchronous and retry + synchronous_cells.on() + resp = app.get('/test_basket_cell/') + assert len(resp.pyquery('.lingo-basket-cell')) == 0 + assert 'Running' in resp.pyquery('.lingo-recent-transactions-cell').text() + assert payment_status.call_count == 1 # transactions cell polled + payment_status.reset_mock() + + resp = pay_resp.click('Pay') + assert payment_status.call_count == 1 # pay polled + payment_status.reset_mock() + + resp = resp.follow() + assert 'Some items are already paid or' in resp + assert len(resp.pyquery('.lingo-basket-cell')) == 0 + assert 'Running' in resp.pyquery('.lingo-recent-transactions-cell').text() + assert payment_status.call_count == 1 # transactions cell polled + payment_status.reset_mock() # Simulate paid status on polling payment_status.return_value = eopayment.common.PaymentResponse( @@ -2193,12 +2220,17 @@ class TestPolling: assert 'foo item: 42.00' in resp assert 'Pay' not in resp assert 'Running' not in resp + assert len(resp.pyquery('.lingo-basket-cell')) == 0 + assert '42.00' in resp.pyquery('.lingo-recent-transactions-cell').text() + assert payment_status.call_count == 1 # transactions cell polled + payment_status.reset_mock() @mock.patch('eopayment.payfip_ws.Payment.payment_status') def test_exception_during_polling( self, payment_status, app, + synchronous_cells, caplog, ): # Try to pay