lingo: allow requiring individual payment for regie (#46503)

This commit is contained in:
Valentin Deniaud 2020-09-23 14:29:19 +02:00
parent 3faa37405b
commit 4ff5f921c1
7 changed files with 91 additions and 6 deletions

View File

@ -87,7 +87,8 @@ class RegieForm(forms.ModelForm):
class Meta:
model = Regie
fields = ['label', 'slug', 'description', 'payment_backend', 'is_default',
'webservice_url', 'extra_fees_ws_url', 'payment_min_amount', 'text_on_success']
'webservice_url', 'extra_fees_ws_url', 'payment_min_amount', 'text_on_success',
'can_pay_only_one_basket_item']
def __init__(self, *args, **kwargs):
super(RegieForm, self).__init__(*args, **kwargs)
@ -107,6 +108,12 @@ class RegieForm(forms.ModelForm):
instance.save()
return instance
def clean(self):
cleaned_data = super().clean()
if cleaned_data['webservice_url'] and cleaned_data['can_pay_only_one_basket_item']:
raise ValidationError('Individual item payment is incompatible with remote regie.')
return cleaned_data
class PaymentBackendForm(forms.ModelForm):

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.18 on 2020-10-01 11:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lingo', '0040_auto_20200608_1222'),
]
operations = [
migrations.AddField(
model_name='regie',
name='can_pay_only_one_basket_item',
field=models.BooleanField(default=False, verbose_name='Basket items must be paid individually'),
),
]

View File

@ -145,6 +145,9 @@ class Regie(models.Model):
payment_backend = models.ForeignKey(
PaymentBackend, on_delete=models.CASCADE, verbose_name=_('Payment backend'))
transaction_options = JSONField(blank=True, verbose_name=_('Transaction Options'))
can_pay_only_one_basket_item = models.BooleanField(
default=False, verbose_name=_('Basket items must be paid individually')
)
def is_remote(self):
return self.webservice_url != ''

View File

@ -4,22 +4,31 @@
<h2>{% trans "Basket" %}</h2>
{% for regie_info in regies %}
{% if regies|length != 1 %}<h3 class="regie-name">{{regie_info.regie.label}}</h3>{% endif %}
<form action="{% url 'lingo-pay' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="next_url" value="{{ cell.page.get_online_url }}" />
<input type="hidden" name="regie" value="{{regie_info.regie.id}}" />
<ul>
<ul class="payment-items">
{% for item in regie_info.items %}
<li><a {% if item.source_url %}href="{{ item.source_url }}{% endif %}">{{ item.subject }}</a>: {{ item.amount }} €
{% if item.user_cancellable %}
<a rel="popup" href="{% url 'lingo-cancel-item' pk=item.id %}">({% trans 'remove' %})</a>
{% endif %}
{% if regie_info.regie.can_pay_only_one_basket_item %}
<a id="{{ item.pk }}" class="button individual-item" href="{{ item.payment_url }}?next_url={{ cell.page.get_online_url }}">{% trans "Pay" %}</a>
{% endif %}
</li>
{% endfor %}
{% if not regie_info.regie.can_pay_only_one_basket_item %}
<li><strong>{% trans "Total:" %}</strong> {{ regie_info.total }} €</li>
{% endif %}
</ul>
{% if not regie_info.regie.can_pay_only_one_basket_item %}
<form action="{% url 'lingo-pay' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="next_url" value="{{ cell.page.get_online_url }}" />
<input type="hidden" name="regie" value="{{regie_info.regie.id}}" />
<button>{% trans "Pay" %}</button>
</form>
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}

View File

@ -457,6 +457,10 @@ class PayView(PayMixin, View):
regie.compute_extra_fees(user=user)
items = BasketItem.get_items_to_be_paid(user=user).filter(regie=regie)
if regie.can_pay_only_one_basket_item and len(items) > 1:
messages.error(request, _('Grouping basket items is not allowed.'))
return HttpResponseRedirect(next_url)
if items:
capture_date = items[0].capture_date
for item in items:

View File

@ -95,6 +95,25 @@ def test_basket_cell(regie, user):
item.save()
assert cell.get_badge(context) == {'badge': u'123.45€'}
def test_basket_cell_can_pay_only_one_basket_item(regie, user):
regie.can_pay_only_one_basket_item = True
regie.save()
page = Page(title='xxx', slug='test_basket_cell', template_name='standard')
page.save()
cell = LingoBasketCell(page=page, placeholder='content', order=0)
item = BasketItem.objects.create(user=user, regie=regie, subject='foo', amount=123)
item2 = BasketItem.objects.create(user=user, regie=regie, subject='bar', amount=123)
context = {'request': RequestFactory(user=user).get('/')}
context['request'].user = user
assert cell.is_relevant(context)
content = cell.render(context)
assert content.count('Pay') == 2
assert item.payment_url in content
assert not 'Total' in content
def test_recent_transaction_cell(regie, user):
page = Page(title='xxx', slug='test_basket_cell', template_name='standard')
page.save()

View File

@ -1531,3 +1531,26 @@ def test_bank_transaction_date(app, key, regie, user, john_doe, caplog, transact
else:
assert transaction.bank_transaction_date == transaction_date
assert 'new transaction_date for transaction' in caplog.text
def test_successfull_items_can_pay_only_one_basket_item(app, basket_page, regie, user):
regie.can_pay_only_one_basket_item = True
regie.save()
item = BasketItem.objects.create(user=user, regie=regie, amount=42, subject='foo item')
item2 = BasketItem.objects.create(user=user, regie=regie, amount=84, subject='bar item')
resp = login(app).get('/test_basket_cell/')
assert 'foo item' in resp.text
assert 'bar item' in resp.text
resp = resp.click('Pay', href=item.payment_url)
# successful payment
qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
args = {'transaction_id': qs['transaction_id'][0], 'signed': True, 'ok': True, 'reason': 'Paid'}
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
resp = app.get(get_url(True, 'lingo-callback', regie), params=args)
resp = app.get('/test_basket_cell/')
assert 'foo item' not in resp.text
assert 'bar item' in resp.text