lingo: support can_pay_only_one on remote regie (#50067)

This commit is contained in:
Thomas NOËL 2021-01-12 12:23:50 +01:00 committed by Thomas NOËL
parent fb4f5fd33d
commit 71aa546fec
3 changed files with 60 additions and 27 deletions

View File

@ -109,12 +109,6 @@ class RegieForm(forms.ModelForm):
instance.save() instance.save()
return instance 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): class PaymentBackendForm(forms.ModelForm):

View File

@ -360,13 +360,12 @@ class PayMixin(object):
self, request, regie, items, remote_items, next_url='/', email='', firstname='', self, request, regie, items, remote_items, next_url='/', email='', firstname='',
lastname=''): lastname=''):
# check contract # check contract
assert bool(len(items)) != bool(len(remote_items)), ( if bool(len(items)) == bool(len(remote_items)):
'there should be at least one item or remote item to pay and not both items' messages.error(request, _('Items to pay are missing or are not of the same type (local/remote).'))
) return HttpResponseRedirect(next_url)
assert not regie.can_pay_only_one_basket_item or len(items) == 1, ( if regie.can_pay_only_one_basket_item and (len(items) > 1 or len(remote_items) > 1):
'regie can only pay one basket item, but handle_payment() ' messages.error(request, _('This regie allows to pay only one item.'))
'did not receive one item: len(items) = %d' % len(items) return HttpResponseRedirect(next_url)
)
total_amount = sum([x.amount for x in remote_items or items]) total_amount = sum([x.amount for x in remote_items or items])
@ -418,14 +417,14 @@ class PayMixin(object):
# copy command reference / invoice number # copy command reference / invoice number
if item.reference_id: if item.reference_id:
kwargs['orderid'] = item.reference_id kwargs['orderid'] = item.reference_id
# PayFiP/TIPI specific if getattr(item, 'request_data', None):
if regie.payment_backend.service in ('payfip_ws', 'tipi'): # PayFiP/TIPI specific
if item.request_data and item.request_data.get('exer') and item.request_data.get('refdet'): if regie.payment_backend.service in ('payfip_ws', 'tipi'):
kwargs['exer'] = item.request_data['exer'] if item.request_data.get('exer') and item.request_data.get('refdet'):
kwargs['refdet'] = item.request_data['refdet'] kwargs['exer'] = item.request_data['exer']
# allow easy testing/use of backend specific keyword arguments kwargs['refdet'] = item.request_data['refdet']
EOPAYMENT_REQUEST_KWARGS_PREFIX = 'eopayment_request_kwargs_' # allow easy testing/use of backend specific keyword arguments
if hasattr(item, 'request_data'): EOPAYMENT_REQUEST_KWARGS_PREFIX = 'eopayment_request_kwargs_'
for key in item.request_data: for key in item.request_data:
if key.startswith(EOPAYMENT_REQUEST_KWARGS_PREFIX): if key.startswith(EOPAYMENT_REQUEST_KWARGS_PREFIX):
arg_name = key[len(EOPAYMENT_REQUEST_KWARGS_PREFIX):] arg_name = key[len(EOPAYMENT_REQUEST_KWARGS_PREFIX):]
@ -495,11 +494,11 @@ class PayView(PayMixin, View):
regie.compute_extra_fees(user=user) regie.compute_extra_fees(user=user)
items = BasketItem.get_items_to_be_paid(user=user).filter(regie=regie) items = BasketItem.get_items_to_be_paid(user=user).filter(regie=regie)
if regie.can_pay_only_one_basket_item and len(items) > 1: if regie.can_pay_only_one_basket_item and (len(items) > 1 or len(remote_items) > 1):
messages.error(request, _('Grouping basket items is not allowed.')) messages.error(request, _('Grouping basket items is not allowed.'))
logger.error('lingo: regie can only pay one basket item, but handle_payment() received', logger.error('lingo: regie can only pay one basket item, but handle_payment() received',
extra={'regie': str(regie), 'items': items, 'remote_items': remote_items}) extra={'regie': str(regie), 'items': items, 'remote_items': remote_items})
return HttpResponseRedirect(next_url) return HttpResponseRedirect(next_url)
if items: if items:
capture_date = items[0].capture_date capture_date = items[0].capture_date

View File

@ -42,6 +42,23 @@ INVOICES = [
'paid': False, 'paid': False,
'payment_date': '1970-01-01', 'payment_date': '1970-01-01',
'no_online_payment_reason': '', 'no_online_payment_reason': '',
'reference_id': 'order-id-1',
},
{
'id': 'F201602',
'display_id': 'F-2016-Two',
'label': 'invoice-two',
'regie': 'remote',
'created': '2016-02-02',
'pay_limit_date': '2999-12-31',
'total_amount': '543.21',
'amount': '543.21',
'has_pdf': True,
'online_payment': True,
'paid': False,
'payment_date': '1970-01-01',
'no_online_payment_reason': '',
'reference_id': 'order-id-2',
}, },
] ]
@ -87,6 +104,7 @@ class MockUser(object):
@mock.patch('combo.utils.requests_wrapper.RequestsSession.send') @mock.patch('combo.utils.requests_wrapper.RequestsSession.send')
def test_remote_regie_active_invoices_cell(mock_send, remote_regie): def test_remote_regie_active_invoices_cell(mock_send, remote_regie):
assert remote_regie.is_remote() == True assert remote_regie.is_remote() == True
assert remote_regie.can_pay_only_one_basket_item is False
page = Page(title='xxx', slug='test_basket_cell', template_name='standard') page = Page(title='xxx', slug='test_basket_cell', template_name='standard')
page.save() page.save()
@ -108,6 +126,8 @@ def test_remote_regie_active_invoices_cell(mock_send, remote_regie):
content = cell.render(context) content = cell.render(context)
assert 'F-2016-One' in content assert 'F-2016-One' in content
assert '123.45' in content assert '123.45' in content
assert 'F-2016-Two' in content
assert '543.21' in content
assert '?page=%s' % page.pk in content assert '?page=%s' % page.pk in content
# check if regie webservice has been correctly called # check if regie webservice has been correctly called
@ -199,11 +219,14 @@ def test_remote_regie_past_invoices_cell(mock_send, remote_regie):
content = cell.render(context) content = cell.render(context)
assert 'F-2016-One' in content assert 'F-2016-One' in content
assert '123.45' in content assert '123.45' in content
assert 'F-2016-Two' in content
assert '543.21' in content
assert 'class="invoice-payment-limit-date"' in content assert 'class="invoice-payment-limit-date"' in content
# invoice without limit date # invoice without limit date
invoices = copy.deepcopy(INVOICES) invoices = copy.deepcopy(INVOICES)
invoices[0]['pay_limit_date'] = '' invoices[0]['pay_limit_date'] = ''
invoices[1]['pay_limit_date'] = ''
ws_invoices = {'err': 0, 'data': invoices} ws_invoices = {'err': 0, 'data': invoices}
mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices)) mock_response = mock.Mock(status_code=200, content=json.dumps(ws_invoices))
mock_response.json.return_value = ws_invoices mock_response.json.return_value = ws_invoices
@ -592,9 +615,12 @@ def test_remote_item_payment_failure(mock_post, mock_get, mock_pay_invoice, app,
@mock.patch('combo.apps.lingo.models.Regie.pay_invoice') @mock.patch('combo.apps.lingo.models.Regie.pay_invoice')
@mock.patch('combo.apps.lingo.models.requests.get') @mock.patch('combo.apps.lingo.models.requests.get')
def test_remote_invoice_successfull_payment_redirect(mock_get, mock_pay_invoice, app, remote_regie): def test_remote_invoice_successfull_payment_redirect(mock_get, mock_pay_invoice, app, remote_regie):
assert remote_regie.is_remote()
assert remote_regie.can_pay_only_one_basket_item is False
remote_regie.save()
page = Page(title='xxx', slug='active-remote-invoices-page', template_name='standard') page = Page(title='xxx', slug='active-remote-invoices-page', template_name='standard')
page.save() page.save()
assert remote_regie.is_remote()
encrypt_id = aes_hex_encrypt(settings.SECRET_KEY, force_bytes('F201601')) encrypt_id = aes_hex_encrypt(settings.SECRET_KEY, force_bytes('F201601'))
mock_json = mock.Mock() mock_json = mock.Mock()
mock_json.json.return_value = {'err': 0, 'data': INVOICES[0]} mock_json.json.return_value = {'err': 0, 'data': INVOICES[0]}
@ -612,6 +638,8 @@ def test_remote_invoice_successfull_payment_redirect(mock_get, mock_pay_invoice,
parsed = urlparse.urlparse(location) parsed = urlparse.urlparse(location)
# get return_url and transaction id from location # get return_url and transaction id from location
qs = urlparse.parse_qs(parsed.query) qs = urlparse.parse_qs(parsed.query)
assert 'orderid' not in qs
assert 'subject' not in qs
args = {'transaction_id': qs['transaction_id'][0], 'signed': True, args = {'transaction_id': qs['transaction_id'][0], 'signed': True,
'ok': True, 'reason': 'Paid'} 'ok': True, 'reason': 'Paid'}
resp = app.get(qs['return_url'][0], params=args) resp = app.get(qs['return_url'][0], params=args)
@ -622,6 +650,18 @@ def test_remote_invoice_successfull_payment_redirect(mock_get, mock_pay_invoice,
assert urlparse.urlparse(resp.html.find('a', {'id': 'next-url'})['href']).path == \ assert urlparse.urlparse(resp.html.find('a', {'id': 'next-url'})['href']).path == \
'/active-remote-invoices-page/' '/active-remote-invoices-page/'
# one item limitation: send orderid to eopayment
remote_regie.can_pay_only_one_basket_item = True
remote_regie.save()
resp = form.submit()
assert resp.status_code == 302
location = resp.location
assert 'dummy-payment' in location
parsed = urlparse.urlparse(location)
qs = urlparse.parse_qs(parsed.query)
assert qs['orderid'] == ['order-id-1']
assert qs['subject'] == ['invoice-one']
@mock.patch('combo.apps.lingo.models.UserSAMLIdentifier') @mock.patch('combo.apps.lingo.models.UserSAMLIdentifier')
@mock.patch('combo.apps.lingo.models.requests.get') @mock.patch('combo.apps.lingo.models.requests.get')