2018-08-22 17:50:13 +02:00
|
|
|
from contextlib import contextmanager
|
2016-07-10 12:30:13 +02:00
|
|
|
import eopayment
|
2015-12-25 21:16:44 +01:00
|
|
|
import pytest
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
import urllib
|
|
|
|
from decimal import Decimal
|
|
|
|
import json
|
2016-08-21 12:53:03 +02:00
|
|
|
import mock
|
2015-12-25 21:16:44 +01:00
|
|
|
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.core.urlresolvers import reverse
|
|
|
|
from django.core.wsgi import get_wsgi_application
|
2015-12-31 16:16:04 +01:00
|
|
|
from django.conf import settings
|
2016-07-10 12:30:13 +02:00
|
|
|
from django.utils import timezone
|
2018-07-25 16:32:50 +02:00
|
|
|
from django.utils.six.moves.urllib import parse as urlparse
|
2016-11-26 08:17:21 +01:00
|
|
|
from django.contrib.messages.storage.session import SessionStorage
|
2015-12-25 21:16:44 +01:00
|
|
|
from webtest import TestApp
|
|
|
|
|
2016-11-26 08:17:21 +01:00
|
|
|
from combo.data.models import Page
|
2016-08-21 12:53:03 +02:00
|
|
|
from combo.apps.lingo.models import (Regie, BasketItem, Transaction,
|
2016-11-26 08:17:21 +01:00
|
|
|
TransactionOperation, RemoteItem, EXPIRED, LingoBasketCell)
|
2016-07-10 12:30:13 +02:00
|
|
|
from combo.apps.lingo.management.commands.update_transactions import Command as UpdateTransactionsCommand
|
2017-08-17 08:57:47 +02:00
|
|
|
from combo.apps.lingo.management.commands.notify_payments import Command as NotifyPaymentsCommand
|
2015-12-31 16:16:04 +01:00
|
|
|
from combo.utils import sign_url
|
2015-12-25 21:16:44 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
from .test_manager import login
|
2017-11-06 12:07:14 +01:00
|
|
|
|
2015-12-25 21:16:44 +01:00
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
|
|
|
|
|
2018-08-22 17:50:13 +02:00
|
|
|
@contextmanager
|
|
|
|
def check_log(caplog, message):
|
|
|
|
idx = len(caplog.records)
|
|
|
|
yield
|
|
|
|
assert any(message in record.message for record in caplog.records[idx:]), \
|
|
|
|
'%r not found in log records' % message
|
|
|
|
|
|
|
|
|
2015-12-25 21:16:44 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def regie():
|
|
|
|
try:
|
|
|
|
regie = Regie.objects.get(slug='test')
|
|
|
|
except Regie.DoesNotExist:
|
|
|
|
regie = Regie()
|
|
|
|
regie.label = 'Test'
|
|
|
|
regie.slug = 'test'
|
|
|
|
regie.description = 'test'
|
|
|
|
regie.payment_min_amount = Decimal(4.5)
|
|
|
|
regie.service = 'dummy'
|
|
|
|
regie.service_options = {'siret': '1234'}
|
|
|
|
regie.save()
|
|
|
|
return regie
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
@pytest.fixture
|
|
|
|
def basket_page():
|
|
|
|
page = Page(title='xxx', slug='test_basket_cell', template_name='standard')
|
|
|
|
page.save()
|
|
|
|
cell = LingoBasketCell(page=page, placeholder='content', order=0)
|
|
|
|
cell.save()
|
|
|
|
return page
|
|
|
|
|
2015-12-25 21:16:44 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def user():
|
|
|
|
try:
|
|
|
|
user = User.objects.get(username='admin')
|
|
|
|
except User.DoesNotExist:
|
2016-11-26 08:17:21 +01:00
|
|
|
user = User.objects.create_user('admin', password='admin',
|
|
|
|
email='foo@example.com')
|
2015-12-25 21:16:44 +01:00
|
|
|
return user
|
|
|
|
|
2016-09-06 14:33:37 +02:00
|
|
|
@pytest.fixture(params=['orig', 'sign_key'])
|
|
|
|
def key(request, settings):
|
|
|
|
if request.param == 'orig':
|
|
|
|
key = 'abcde'
|
|
|
|
settings.KNOWN_SERVICES = {
|
|
|
|
'wcs': {
|
|
|
|
'wcs1': {
|
2016-11-26 08:17:21 +01:00
|
|
|
'url': 'http://example.org/',
|
2016-09-06 14:33:37 +02:00
|
|
|
'verif_orig': 'wcs',
|
|
|
|
'secret': key,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return key
|
|
|
|
else:
|
|
|
|
return settings.LINGO_API_SIGN_KEY
|
|
|
|
|
2016-09-27 17:06:17 +02:00
|
|
|
def test_default_regie():
|
|
|
|
Regie.objects.all().delete()
|
|
|
|
regie1 = Regie(label='foo', slug='foo')
|
|
|
|
regie1.save()
|
|
|
|
assert bool(regie1.is_default) is True
|
|
|
|
regie2 = Regie(label='bar', slug='bar')
|
|
|
|
regie2.save()
|
|
|
|
assert bool(regie2.is_default) is False
|
|
|
|
|
|
|
|
regie2.is_default = True
|
|
|
|
regie2.save()
|
|
|
|
regie2 = Regie.objects.get(id=regie2.id)
|
|
|
|
assert bool(regie2.is_default) is True
|
|
|
|
regie1 = Regie.objects.get(id=regie1.id)
|
|
|
|
assert bool(regie1.is_default) is False
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_regie_api(app):
|
|
|
|
resp = app.get(reverse('api-regies'))
|
2016-11-11 14:02:42 +01:00
|
|
|
assert len(json.loads(resp.content).get('data')) == 0
|
|
|
|
test_default_regie()
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(reverse('api-regies'))
|
2016-11-11 14:02:42 +01:00
|
|
|
assert len(json.loads(resp.content).get('data')) == 2
|
|
|
|
assert json.loads(resp.content).get('data')[0]['id'] == Regie.objects.get(is_default=True).slug
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_payment_min_amount(app, basket_page, regie, user):
|
2015-12-25 21:16:44 +01:00
|
|
|
items = {'item1': {'amount': '1.5', 'source_url': '/item/1'},
|
|
|
|
'item2': {'amount': '2.4', 'source_url': '/item/2'}
|
|
|
|
}
|
|
|
|
b_items = []
|
2018-07-25 16:32:50 +02:00
|
|
|
for subject, details in items.items():
|
2015-12-25 21:16:44 +01:00
|
|
|
b_item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject=subject, **details)
|
|
|
|
b_items.append(b_item.pk)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get('/test_basket_cell/')
|
|
|
|
resp = resp.form.submit()
|
2016-02-25 11:43:28 +01:00
|
|
|
assert resp.status_code == 302
|
2015-12-25 21:16:44 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_successfull_items_payment(app, basket_page, regie, user):
|
2016-10-21 14:06:51 +02:00
|
|
|
items = {'item1': {'amount': '10.5', 'source_url': 'http://example.org/item/1'},
|
|
|
|
'item2': {'amount': '42', 'source_url': 'http://example.org/item/2'},
|
|
|
|
'item3': {'amount': '100', 'source_url': 'http://example.org/item/3'},
|
|
|
|
'item4': {'amount': '354', 'source_url': 'http://example.org/item/4'}
|
2015-12-25 21:16:44 +01:00
|
|
|
}
|
|
|
|
b_items = []
|
2018-07-25 16:32:50 +02:00
|
|
|
for subject, details in items.items():
|
2015-12-25 21:16:44 +01:00
|
|
|
b_item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject=subject, **details)
|
|
|
|
b_items.append(b_item.pk)
|
2018-07-25 16:32:50 +02:00
|
|
|
|
|
|
|
resp = login(app).get('/test_basket_cell/')
|
|
|
|
resp = resp.form.submit()
|
2015-12-25 21:16:44 +01:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2015-12-25 21:16:44 +01:00
|
|
|
assert 'dummy-payment' in location
|
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
# get return_url and transaction id from location
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
args = {'transaction_id': qs['transaction_id'][0], 'signed': True,
|
|
|
|
'ok': True, 'reason': 'Paid'}
|
2016-02-16 19:43:14 +01:00
|
|
|
# make sure return url is the user return URL
|
|
|
|
assert urlparse.urlparse(qs['return_url'][0]).path.startswith(
|
|
|
|
reverse('lingo-return', kwargs={'regie_pk': regie.id}))
|
|
|
|
# simulate successful call to callback URL
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(reverse('lingo-callback', kwargs={'regie_pk': regie.id}), params=args)
|
2015-12-25 21:16:44 +01:00
|
|
|
assert resp.status_code == 200
|
2017-10-11 17:20:56 +02:00
|
|
|
# simulate successful return URL
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(qs['return_url'][0], params=args)
|
2017-10-11 17:20:56 +02:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
assert urlparse.urlparse(resp.url).path == '/test_basket_cell/'
|
|
|
|
resp = resp.follow()
|
|
|
|
assert 'Your payment has been succesfully registered.' in resp.text
|
2015-12-25 21:16:44 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_add_amount_to_basket(app, key, regie, user):
|
2017-11-06 12:07:14 +01:00
|
|
|
other_regie = Regie(label='test2', slug='test2', service='dummy', service_options={'siret': '1234'})
|
2016-09-27 17:06:17 +02:00
|
|
|
other_regie.save()
|
|
|
|
|
2015-12-25 21:16:44 +01:00
|
|
|
user_email = 'foo@example.com'
|
|
|
|
User.objects.get_or_create(email=user_email)
|
|
|
|
amount = 42
|
|
|
|
data = {'amount': amount, 'display_name': 'test amount',
|
|
|
|
'url': 'http://example.com'}
|
2016-09-06 14:33:37 +02:00
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2015-12-25 21:16:44 +01:00
|
|
|
assert resp.status_code == 200
|
2016-05-26 13:04:47 +02:00
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
2015-12-25 21:16:44 +01:00
|
|
|
assert BasketItem.objects.filter(amount=amount).exists()
|
2016-09-27 17:06:17 +02:00
|
|
|
assert BasketItem.objects.filter(amount=amount)[0].regie_id == regie.id
|
2015-12-25 21:16:44 +01:00
|
|
|
|
|
|
|
data['extra'] = {'amount': '22.22'}
|
2016-11-09 01:16:54 +01:00
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
|
2016-09-06 14:33:37 +02:00
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2015-12-25 21:16:44 +01:00
|
|
|
assert resp.status_code == 200
|
2016-05-26 13:04:47 +02:00
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
2015-12-25 21:16:44 +01:00
|
|
|
assert BasketItem.objects.filter(amount=Decimal('64.22')).exists()
|
|
|
|
|
|
|
|
data['amount'] = [amount]
|
|
|
|
data['extra'] = {'amount': ['22.22', '12']}
|
2016-11-09 01:16:54 +01:00
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json('%s&amount=5' % url, params=data)
|
2015-12-25 21:16:44 +01:00
|
|
|
assert resp.status_code == 200
|
2016-05-26 13:04:47 +02:00
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
2015-12-25 21:16:44 +01:00
|
|
|
assert BasketItem.objects.filter(amount=Decimal('81.22')).exists()
|
|
|
|
|
2016-09-27 17:06:17 +02:00
|
|
|
other_regie.is_default = True
|
|
|
|
other_regie.save()
|
|
|
|
data['amount'] = []
|
|
|
|
data['extra'] = {'amount': '22.23'}
|
2016-11-09 01:16:54 +01:00
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
|
2016-09-27 17:06:17 +02:00
|
|
|
url = sign_url(url, settings.LINGO_API_SIGN_KEY)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-09-27 17:06:17 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=Decimal('22.23')).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=Decimal('22.23'))[0].regie_id == other_regie.id
|
|
|
|
|
|
|
|
url = '%s?email=%s®ie_id=%s' % (
|
|
|
|
reverse('api-add-basket-item'), user_email, regie.id)
|
2017-05-28 12:47:24 +02:00
|
|
|
data['extra'] = {'amount': '22.24', 'foo': 'bar'}
|
2016-09-27 17:06:17 +02:00
|
|
|
url = sign_url(url, settings.LINGO_API_SIGN_KEY)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-09-27 17:06:17 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=Decimal('22.24')).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=Decimal('22.24'))[0].regie_id == regie.id
|
2017-05-28 12:47:24 +02:00
|
|
|
assert BasketItem.objects.filter(amount=Decimal('22.24'))[0].request_data == data['extra']
|
2016-09-27 17:06:17 +02:00
|
|
|
|
2016-11-10 20:22:09 +01:00
|
|
|
url = '%s?email=%s®ie_id=%s' % (
|
|
|
|
reverse('api-add-basket-item'), user_email, regie.slug)
|
|
|
|
data['extra'] = {'amount': '13.67'}
|
|
|
|
url = sign_url(url, settings.LINGO_API_SIGN_KEY)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-11-10 20:22:09 +01:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=Decimal('13.67')).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=Decimal('13.67'))[0].regie_id == regie.id
|
|
|
|
|
|
|
|
url = '%s?email=%s&orig=wcs®ie_id=%s' % (reverse('api-add-basket-item'), user_email, 'scarecrow')
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data, status=400)
|
|
|
|
assert resp.text == 'Unknown regie'
|
2016-11-10 20:22:09 +01:00
|
|
|
|
2017-11-06 12:07:14 +01:00
|
|
|
def test_pay_multiple_regies(app, key, regie, user):
|
2018-07-25 16:32:50 +02:00
|
|
|
test_add_amount_to_basket(app, key, regie, user)
|
2017-11-06 12:07:14 +01:00
|
|
|
|
|
|
|
page = Page(title='xxx', slug='test_basket_cell', template_name='standard')
|
|
|
|
page.save()
|
|
|
|
cell = LingoBasketCell(page=page, placeholder='content', order=0)
|
|
|
|
cell.save()
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(page.get_online_url())
|
2017-11-06 12:07:14 +01:00
|
|
|
resp = resp.forms[0].submit()
|
|
|
|
assert resp.location.startswith('http://dummy-payment.demo.entrouvert.com/')
|
|
|
|
qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
|
|
|
|
assert qs['amount'] == ['223.35']
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(page.get_online_url())
|
2017-11-06 12:07:14 +01:00
|
|
|
resp = resp.forms[1].submit()
|
|
|
|
qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
|
|
|
|
assert qs['amount'] == ['22.23']
|
|
|
|
|
2017-11-15 08:19:09 +01:00
|
|
|
def test_pay_as_anonymous_user(app, key, regie, user):
|
2018-07-25 16:32:50 +02:00
|
|
|
test_add_amount_to_basket(app, key, regie, user)
|
2017-11-15 08:19:09 +01:00
|
|
|
|
|
|
|
page = Page(title='xxx', slug='test_basket_cell', template_name='standard')
|
|
|
|
page.save()
|
|
|
|
cell = LingoBasketCell(page=page, placeholder='content', order=0)
|
|
|
|
cell.save()
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(page.get_online_url())
|
2017-11-15 08:19:09 +01:00
|
|
|
app.cookiejar.clear(domain='testserver.local', path='/', name='sessionid')
|
|
|
|
resp = resp.forms[0].submit().follow()
|
2018-07-25 16:32:50 +02:00
|
|
|
assert 'Payment requires to be logged in.' in resp.text
|
2017-11-15 08:19:09 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_cancel_basket_item(app, key, regie, user):
|
2016-05-26 13:04:47 +02:00
|
|
|
user_email = 'foo@example.com'
|
|
|
|
User.objects.get_or_create(email=user_email)
|
2016-09-06 14:33:37 +02:00
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
|
|
|
|
url = sign_url(url, key)
|
2017-04-07 17:44:42 +02:00
|
|
|
data = {'amount': 42, 'display_name': 'test amount', 'url':
|
|
|
|
'http://example.com/', 'notify': 'true'}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-05-26 13:04:47 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists()
|
|
|
|
basket_item_id = json.loads(resp.content)['id']
|
|
|
|
|
2017-04-07 17:44:42 +02:00
|
|
|
data = {'amount': 21, 'display_name': 'test amount', 'url': 'http://example.net/'}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-05-26 13:04:47 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=21, cancellation_date__isnull=True).exists()
|
2017-04-07 17:44:42 +02:00
|
|
|
basket_item_id_2 = json.loads(resp.content)['id']
|
|
|
|
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-04-07 17:44:42 +02:00
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-remove-basket-item'), user_email)
|
|
|
|
url = sign_url(url, key)
|
|
|
|
data = {'basket_item_id': basket_item_id, 'notify': 'true'}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2017-04-07 17:44:42 +02:00
|
|
|
assert request.call_args[0] == ('POST', u'http://example.com/jump/trigger/cancelled')
|
|
|
|
assert not BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=21, cancellation_date__isnull=True).exists()
|
|
|
|
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-04-07 17:44:42 +02:00
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-remove-basket-item'), user_email)
|
|
|
|
url = sign_url(url, key)
|
|
|
|
data = {'basket_item_id': basket_item_id_2}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2017-04-07 17:44:42 +02:00
|
|
|
assert request.call_count == 0
|
|
|
|
assert not BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists()
|
|
|
|
assert not BasketItem.objects.filter(amount=21, cancellation_date__isnull=True).exists()
|
2016-05-26 13:04:47 +02:00
|
|
|
|
2015-12-25 21:16:44 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_cancel_basket_item_from_cell(app, key, regie, user):
|
2016-11-26 08:17:21 +01:00
|
|
|
page = Page(title='xxx', slug='test_basket_cell', template_name='standard')
|
|
|
|
page.save()
|
|
|
|
cell = LingoBasketCell(page=page, placeholder='content', order=0)
|
|
|
|
cell.save()
|
|
|
|
|
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user.email)
|
|
|
|
url = sign_url(url, key)
|
|
|
|
data = {'amount': 42, 'display_name': 'test amount', 'url': 'http://example.org/testitem/'}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-11-26 08:17:21 +01:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists()
|
|
|
|
basket_item_id = json.loads(resp.content)['id']
|
|
|
|
|
|
|
|
# check while not logged in
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(reverse('lingo-cancel-item', kwargs={'pk': basket_item_id}), status=404)
|
2016-11-26 08:17:21 +01:00
|
|
|
assert BasketItem.objects.filter(id=basket_item_id).exists()
|
|
|
|
|
|
|
|
# check a successful case
|
2018-07-25 16:32:50 +02:00
|
|
|
app = login(app)
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(reverse('lingo-cancel-item', kwargs={'pk': basket_item_id}))
|
|
|
|
resp = resp.form.submit()
|
2016-11-26 08:17:21 +01:00
|
|
|
url = request.call_args[0][1]
|
|
|
|
assert url.startswith('http://example.org/testitem/jump/trigger/cancelled')
|
|
|
|
assert BasketItem.objects.filter(id=basket_item_id, cancellation_date__isnull=False).exists()
|
|
|
|
|
|
|
|
# check removal of an item that is not cancellable
|
|
|
|
url = '%s?email=%s&cancellable=no&orig=wcs' % (reverse('api-add-basket-item'), user.email)
|
|
|
|
url = sign_url(url, key)
|
|
|
|
data = {'amount': 21, 'display_name': 'test amount',
|
|
|
|
'url': 'http://example.org/testitem/'}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-11-26 08:17:21 +01:00
|
|
|
basket_item2_id = json.loads(resp.content)['id']
|
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=21, cancellation_date__isnull=True).exists()
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(reverse('lingo-cancel-item', kwargs={'pk': basket_item2_id}))
|
|
|
|
resp = resp.form.submit()
|
|
|
|
resp = resp.follow()
|
|
|
|
assert 'This item cannot be removed.' in resp.text
|
2016-11-26 08:17:21 +01:00
|
|
|
|
|
|
|
# check removal of the item of another user
|
|
|
|
user_email = 'bar@example.com'
|
|
|
|
User.objects.get_or_create(email=user_email)
|
|
|
|
url = '%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email)
|
|
|
|
url = sign_url(url, key)
|
|
|
|
data = {'amount': 42, 'display_name': 'test amount', 'url': 'http://example.org/testitem/'}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2016-11-26 08:17:21 +01:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
basket_item_id = json.loads(resp.content)['id']
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
app.get(reverse('lingo-cancel-item', kwargs={'pk': basket_item_id}), status=404)
|
|
|
|
app.post(reverse('lingo-cancel-item', kwargs={'pk': basket_item_id}), status=403)
|
2016-11-26 08:17:21 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_payment_callback(app, basket_page, regie, user):
|
2018-02-19 13:54:48 +01:00
|
|
|
page = Page(title='xxx', slug='index', template_name='standard')
|
|
|
|
page.save()
|
2015-12-25 21:16:44 +01:00
|
|
|
item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject='test_item', amount='10.5',
|
2016-10-21 14:06:51 +02:00
|
|
|
source_url='http://example.org/testitem/')
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2015-12-25 21:16:44 +01:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2015-12-25 21:16:44 +01:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
2017-05-12 11:41:17 +02:00
|
|
|
assert data['amount'] == '10.50'
|
2015-12-25 21:16:44 +01:00
|
|
|
|
|
|
|
# call callback with GET
|
2016-02-16 19:43:14 +01:00
|
|
|
callback_url = reverse('lingo-callback', kwargs={'regie_pk': regie.id})
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2018-07-25 16:32:50 +02:00
|
|
|
get_resp = app.get(callback_url, params=data)
|
2016-10-21 14:06:51 +02:00
|
|
|
url = request.call_args[0][1]
|
|
|
|
assert url.startswith('http://example.org/testitem/jump/trigger/paid')
|
2015-12-25 21:16:44 +01:00
|
|
|
assert get_resp.status_code == 200
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == 3
|
|
|
|
|
2017-05-12 11:41:17 +02:00
|
|
|
item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject='test_item', amount='11.5',
|
|
|
|
source_url='http://example.org/testitem/')
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2015-12-25 21:16:44 +01:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2015-12-25 21:16:44 +01:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
2017-05-12 11:41:17 +02:00
|
|
|
assert data['amount'] == '11.50'
|
2015-12-25 21:16:44 +01:00
|
|
|
|
|
|
|
# call callback with POST
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2018-07-25 16:32:50 +02:00
|
|
|
post_resp = app.post(callback_url, params=data)
|
2015-12-25 21:16:44 +01:00
|
|
|
assert post_resp.status_code == 200
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == 3
|
2016-02-03 10:49:47 +01:00
|
|
|
|
|
|
|
# call return view
|
2018-07-25 16:32:50 +02:00
|
|
|
get_resp = app.get(reverse('lingo-return', kwargs={'regie_pk': regie.pk}), params=data)
|
2016-02-03 10:49:47 +01:00
|
|
|
assert get_resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(get_resp['Location'])
|
|
|
|
assert 'Your payment has been succesfully registered.' in resp.text
|
2016-02-19 11:13:37 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_payment_callback_no_regie(app, basket_page, regie, user):
|
2017-06-11 13:01:22 +02:00
|
|
|
item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject='test_item', amount='10.5',
|
|
|
|
source_url='http://example.org/testitem/')
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2017-06-11 13:01:22 +02:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2017-06-11 13:01:22 +02:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
|
|
|
assert data['amount'] == '10.50'
|
|
|
|
|
|
|
|
# call callback with GET
|
|
|
|
callback_url = reverse('lingo-callback', kwargs={'regie_pk': regie.id})
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2018-07-25 16:32:50 +02:00
|
|
|
get_resp = app.get(callback_url, params=data)
|
2017-06-11 13:01:22 +02:00
|
|
|
url = request.call_args[0][1]
|
|
|
|
assert url.startswith('http://example.org/testitem/jump/trigger/paid')
|
|
|
|
assert get_resp.status_code == 200
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == 3
|
|
|
|
|
|
|
|
item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject='test_item', amount='11.5',
|
|
|
|
source_url='http://example.org/testitem/')
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2017-06-11 13:01:22 +02:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2017-06-11 13:01:22 +02:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
|
|
|
assert data['amount'] == '11.50'
|
2016-02-19 11:13:37 +01:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_nonexisting_transaction(app, regie, user):
|
|
|
|
app = login(app)
|
2016-02-19 11:13:37 +01:00
|
|
|
data = {'transaction_id': 'unknown', 'signed': True,
|
|
|
|
'amount': '23', 'ok': True}
|
|
|
|
|
|
|
|
# call callback with GET
|
|
|
|
callback_url = reverse('lingo-callback', kwargs={'regie_pk': regie.id})
|
2018-07-25 16:32:50 +02:00
|
|
|
app.get(callback_url, params=data, status=404)
|
2016-07-10 12:30:13 +02:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_payment_callback_waiting(app, basket_page, regie, user):
|
2018-01-31 15:25:13 +01:00
|
|
|
item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject='test_item', amount='10.5',
|
|
|
|
source_url='http://example.org/testitem/')
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2018-01-31 15:25:13 +01:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2018-01-31 15:25:13 +01:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'waiting': True}
|
|
|
|
assert data['amount'] == '10.50'
|
|
|
|
|
|
|
|
# callback with WAITING state
|
|
|
|
callback_url = reverse('lingo-callback', kwargs={'regie_pk': regie.id})
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(callback_url, params=data)
|
2018-01-31 15:25:13 +01:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == eopayment.WAITING
|
|
|
|
assert BasketItem.objects.get(id=item.id).waiting_date
|
|
|
|
assert not BasketItem.objects.get(id=item.id).payment_date
|
|
|
|
assert BasketItem.get_items_to_be_paid(user).count() == 0
|
|
|
|
|
|
|
|
# callback with PAID state
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(callback_url, params=data)
|
2018-01-31 15:25:13 +01:00
|
|
|
assert resp.status_code == 200
|
|
|
|
url = request.call_args[0][1]
|
|
|
|
assert url.startswith('http://example.org/testitem/jump/trigger/paid')
|
|
|
|
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == eopayment.PAID
|
|
|
|
assert BasketItem.objects.get(id=item.id).payment_date
|
|
|
|
assert BasketItem.get_items_to_be_paid(user).count() == 0
|
|
|
|
|
2018-08-22 17:50:13 +02:00
|
|
|
def test_payment_no_callback_just_return(caplog, app, basket_page, regie, user):
|
2018-02-19 13:54:48 +01:00
|
|
|
item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject='test_item', amount='10.5',
|
|
|
|
source_url='http://example.org/testitem/')
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2018-02-19 13:54:48 +01:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2018-02-19 13:54:48 +01:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
|
|
|
assert data['amount'] == '10.50'
|
|
|
|
|
|
|
|
# call return with unsigned POST
|
2018-08-22 17:50:13 +02:00
|
|
|
with check_log(caplog, 'received unsigned payment'):
|
|
|
|
return_url = reverse('lingo-return', kwargs={'regie_pk': regie.id})
|
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
|
|
|
get_resp = app.post(return_url, params=data)
|
|
|
|
assert request.call_count == 0
|
|
|
|
assert get_resp.status_code == 302
|
|
|
|
assert urlparse.urlparse(get_resp['location']).path == '/test_basket_cell/'
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == 0 # not paid
|
|
|
|
|
|
|
|
# call return with missing data
|
|
|
|
with check_log(caplog, 'failed to process payment response: missing transaction_id'):
|
|
|
|
baddata = data.copy()
|
|
|
|
del baddata['transaction_id']
|
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
|
|
|
get_resp = app.post(return_url, params=baddata)
|
|
|
|
assert get_resp.status_code == 302
|
|
|
|
resp = app.get(get_resp['Location'])
|
|
|
|
assert 'Your payment has been succesfully registered.' not in resp.text
|
|
|
|
assert 'the payment service failed to provide a correct answer.' in resp.text
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == 0 # not paid
|
2018-02-19 13:54:48 +01:00
|
|
|
|
|
|
|
# call return with signed POST
|
|
|
|
data['signed'] = True
|
|
|
|
return_url = reverse('lingo-return', kwargs={'regie_pk': regie.id})
|
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2018-07-25 16:32:50 +02:00
|
|
|
get_resp = app.post(return_url, params=data)
|
2018-02-19 13:54:48 +01:00
|
|
|
url = request.call_args[0][1]
|
|
|
|
assert url.startswith('http://example.org/testitem/jump/trigger/paid')
|
|
|
|
assert get_resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
assert urlparse.urlparse(get_resp['location']).path == '/test_basket_cell/'
|
|
|
|
resp = app.get(get_resp['Location'])
|
|
|
|
assert 'Your payment has been succesfully registered.' in resp.text
|
2018-02-19 13:54:48 +01:00
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == eopayment.PAID
|
|
|
|
|
2016-07-10 12:30:13 +02:00
|
|
|
def test_transaction_expiration():
|
|
|
|
t1 = Transaction(status=0)
|
|
|
|
t1.save()
|
|
|
|
t1.start_date = timezone.now() - timedelta(hours=2)
|
|
|
|
t1.save()
|
|
|
|
t2 = Transaction(status=0)
|
|
|
|
t2.save()
|
|
|
|
|
|
|
|
cmd = UpdateTransactionsCommand()
|
|
|
|
cmd.handle()
|
|
|
|
|
|
|
|
assert Transaction.objects.get(id=t1.id).status == EXPIRED
|
|
|
|
assert Transaction.objects.get(id=t2.id).status == 0
|
2016-08-21 12:53:03 +02:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_transaction_validate(app, key, regie, user):
|
2016-08-21 12:53:03 +02:00
|
|
|
t1 = Transaction(regie=regie, bank_data={'bank': 'data'}, amount=12,
|
|
|
|
status=eopayment.PAID)
|
|
|
|
t1.save()
|
|
|
|
|
|
|
|
url = reverse('api-validate-transaction') + '?amount=10&transaction_id=0'
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params={}, status=403)
|
2016-08-21 12:53:03 +02:00
|
|
|
|
2016-09-06 14:33:37 +02:00
|
|
|
url = reverse('api-validate-transaction') + '?amount=10&transaction_id=0&orig=wcs'
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params={}, status=404)
|
2016-08-21 12:53:03 +02:00
|
|
|
|
2016-09-06 14:33:37 +02:00
|
|
|
url = reverse('api-validate-transaction') + '?amount=10&transaction_id=%s&orig=wcs' % t1.id
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params={})
|
2016-08-21 12:53:03 +02:00
|
|
|
assert json.loads(resp.content)['err'] == 0
|
|
|
|
operations = TransactionOperation.objects.filter(transaction=t1)
|
|
|
|
assert len(operations) == 1
|
|
|
|
assert operations[0].amount == 10
|
|
|
|
|
|
|
|
with mock.patch.object(eopayment.dummy.Payment, 'validate', autospec=True) as mock_validate:
|
|
|
|
mock_validate.side_effect = eopayment.ResponseError
|
2016-09-06 14:33:37 +02:00
|
|
|
url = reverse('api-validate-transaction') + '?amount=10&transaction_id=%s&orig=wcs' % t1.id
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params={})
|
2016-08-21 12:53:03 +02:00
|
|
|
assert json.loads(resp.content)['err'] == 1
|
|
|
|
assert TransactionOperation.objects.filter(transaction=t1).count() == 1
|
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_transaction_cancel(app, key, regie, user):
|
2016-08-21 12:53:03 +02:00
|
|
|
t1 = Transaction(regie=regie, bank_data={'bank': 'data'}, amount=12,
|
|
|
|
status=eopayment.PAID)
|
|
|
|
t1.save()
|
|
|
|
|
2016-09-06 14:33:37 +02:00
|
|
|
url = reverse('api-cancel-transaction') + '?amount=10&transaction_id=0&orig=wcs'
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params={}, status=403)
|
2016-08-21 12:53:03 +02:00
|
|
|
|
2016-09-06 14:33:37 +02:00
|
|
|
url = reverse('api-cancel-transaction') + '?amount=10&transaction_id=0&orig=wcs'
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post(url, params={}, status=404)
|
2016-08-21 12:53:03 +02:00
|
|
|
|
2016-09-06 14:33:37 +02:00
|
|
|
url = reverse('api-cancel-transaction') + '?amount=10&transaction_id=%s&orig=wcs' % t1.id
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params={})
|
2016-08-21 12:53:03 +02:00
|
|
|
assert json.loads(resp.content)['err'] == 0
|
|
|
|
operations = TransactionOperation.objects.filter(transaction=t1)
|
|
|
|
assert len(operations) == 1
|
|
|
|
assert operations[0].amount == 10
|
|
|
|
|
|
|
|
with mock.patch.object(eopayment.dummy.Payment, 'cancel', autospec=True) as mock_cancel:
|
|
|
|
mock_cancel.side_effect = eopayment.ResponseError
|
2016-09-06 14:33:37 +02:00
|
|
|
url = reverse('api-cancel-transaction') + '?amount=10&transaction_id=%s&orig=wcs' % t1.id
|
|
|
|
url = sign_url(url, key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params={})
|
2016-08-21 12:53:03 +02:00
|
|
|
assert json.loads(resp.content)['err'] == 1
|
|
|
|
assert TransactionOperation.objects.filter(transaction=t1).count() == 1
|
2017-05-28 12:47:24 +02:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_extra_fees(app, basket_page, key, regie, user):
|
2017-05-28 12:47:24 +02:00
|
|
|
regie.extra_fees_ws_url = 'http://www.example.net/extra-fees'
|
|
|
|
regie.save()
|
|
|
|
|
|
|
|
user_email = 'foo@example.com'
|
|
|
|
User.objects.get_or_create(email=user_email)
|
|
|
|
amount = 42
|
|
|
|
data = {'amount': amount, 'display_name': 'test amount'}
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-05-28 12:47:24 +02:00
|
|
|
mock_json = mock.Mock()
|
|
|
|
mock_json.status_code = 200
|
|
|
|
mock_json.json.return_value = {'err': 0, 'data': [{'subject': 'Extra Fees', 'amount': '5'}]}
|
|
|
|
request.return_value = mock_json
|
|
|
|
url = sign_url('%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email), key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2017-05-28 12:47:24 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert BasketItem.objects.filter(amount=amount).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=amount)[0].regie_id == regie.id
|
|
|
|
assert BasketItem.objects.filter(amount=5, extra_fee=True).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=5, extra_fee=True)[0].regie_id == regie.id
|
|
|
|
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-05-28 12:47:24 +02:00
|
|
|
mock_json = mock.Mock()
|
|
|
|
mock_json.status_code = 200
|
|
|
|
mock_json.json.return_value = {'err': 0, 'data': [{'subject': 'Extra Fees', 'amount': '7'}]}
|
|
|
|
request.return_value = mock_json
|
|
|
|
data['amount'] = 43
|
|
|
|
url = sign_url('%s?email=%s&orig=wcs' % (reverse('api-add-basket-item'), user_email), key)
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2017-05-31 09:47:15 +02:00
|
|
|
assert request.call_args[0] == ('POST', 'http://www.example.net/extra-fees')
|
|
|
|
assert len(json.loads(request.call_args[1]['data'])['data']) == 2
|
|
|
|
|
2017-05-28 12:47:24 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert json.loads(resp.content)['result'] == 'success'
|
|
|
|
assert not BasketItem.objects.filter(amount=5, extra_fee=True).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=7, extra_fee=True).exists()
|
|
|
|
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-05-28 12:47:24 +02:00
|
|
|
mock_json = mock.Mock()
|
|
|
|
mock_json.status_code = 200
|
|
|
|
mock_json.json.return_value = {'err': 0, 'data': [{'subject': 'Extra Fees', 'amount': '4'}]}
|
|
|
|
request.return_value = mock_json
|
|
|
|
url = sign_url('%s?email=%s&orig=wcs' % (reverse('api-remove-basket-item'), user_email), key)
|
|
|
|
data = {'basket_item_id': BasketItem.objects.get(amount=43).id}
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.post_json(url, params=data)
|
2017-05-28 12:47:24 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert not BasketItem.objects.filter(amount=7, extra_fee=True).exists()
|
|
|
|
assert BasketItem.objects.filter(amount=4, extra_fee=True).exists()
|
|
|
|
|
|
|
|
# test payment
|
2018-07-25 16:32:50 +02:00
|
|
|
app = login(app)
|
2017-05-28 12:47:24 +02:00
|
|
|
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-05-28 12:47:24 +02:00
|
|
|
mock_json = mock.Mock()
|
|
|
|
mock_json.status_code = 200
|
|
|
|
mock_json.json.return_value = {'err': 0, 'data': [{'subject': 'Extra Fees', 'amount': '2'}]}
|
|
|
|
request.return_value = mock_json
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2017-05-28 12:47:24 +02:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2017-05-28 12:47:24 +02:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
|
|
|
assert data['amount'] == '44.00'
|
|
|
|
|
2017-06-14 15:46:10 +02:00
|
|
|
# test again, without specifying a regie
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-06-14 15:46:10 +02:00
|
|
|
mock_json = mock.Mock()
|
|
|
|
mock_json.status_code = 200
|
|
|
|
mock_json.json.return_value = {'err': 0, 'data': [{'subject': 'Extra Fees', 'amount': '3'}]}
|
|
|
|
request.return_value = mock_json
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2017-06-14 15:46:10 +02:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2017-06-14 15:46:10 +02:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
|
|
|
assert data['amount'] == '45.00'
|
|
|
|
|
2017-05-28 12:47:24 +02:00
|
|
|
# call callback with GET
|
|
|
|
callback_url = reverse('lingo-callback', kwargs={'regie_pk': regie.id})
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = app.get(callback_url, params=data)
|
2017-05-28 12:47:24 +02:00
|
|
|
assert resp.status_code == 200
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == 3
|
2017-08-17 08:57:47 +02:00
|
|
|
|
2018-07-25 16:32:50 +02:00
|
|
|
def test_payment_callback_error(app, basket_page, regie, user):
|
2017-08-17 08:57:47 +02:00
|
|
|
item = BasketItem.objects.create(user=user, regie=regie,
|
|
|
|
subject='test_item', amount='10.5',
|
|
|
|
source_url='http://example.org/testitem/')
|
2018-07-25 16:32:50 +02:00
|
|
|
resp = login(app).get(basket_page.get_online_url())
|
|
|
|
resp = resp.form.submit()
|
2017-08-17 08:57:47 +02:00
|
|
|
assert resp.status_code == 302
|
2018-07-25 16:32:50 +02:00
|
|
|
location = resp.location
|
2017-08-17 08:57:47 +02:00
|
|
|
parsed = urlparse.urlparse(location)
|
|
|
|
qs = urlparse.parse_qs(parsed.query)
|
|
|
|
transaction_id = qs['transaction_id'][0]
|
|
|
|
data = {'transaction_id': transaction_id, 'signed': True,
|
|
|
|
'amount': qs['amount'][0], 'ok': True}
|
|
|
|
assert data['amount'] == '10.50'
|
|
|
|
|
|
|
|
# call callback with GET
|
|
|
|
callback_url = reverse('lingo-callback', kwargs={'regie_pk': regie.id})
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-08-17 08:57:47 +02:00
|
|
|
mock_response = mock.Mock()
|
|
|
|
def kaboom():
|
|
|
|
raise Exception('kaboom')
|
|
|
|
mock_response.status_code = 500
|
|
|
|
mock_response.raise_for_status = kaboom
|
|
|
|
request.return_value = mock_response
|
2018-07-25 16:32:50 +02:00
|
|
|
get_resp = app.get(callback_url, params=data)
|
2017-08-17 08:57:47 +02:00
|
|
|
url = request.call_args[0][1]
|
|
|
|
assert url.startswith('http://example.org/testitem/jump/trigger/paid')
|
|
|
|
assert get_resp.status_code == 200
|
|
|
|
assert Transaction.objects.get(order_id=transaction_id).status == 3
|
|
|
|
assert BasketItem.objects.get(id=item.id).payment_date
|
|
|
|
assert not BasketItem.objects.get(id=item.id).notification_date
|
|
|
|
|
|
|
|
# too soon
|
|
|
|
NotifyPaymentsCommand().handle()
|
|
|
|
assert BasketItem.objects.get(id=item.id).payment_date
|
|
|
|
assert not BasketItem.objects.get(id=item.id).notification_date
|
|
|
|
|
|
|
|
# fake delay
|
|
|
|
basket_item = BasketItem.objects.get(id=item.id)
|
|
|
|
basket_item.payment_date = timezone.now() - timedelta(hours=1)
|
|
|
|
basket_item.save()
|
|
|
|
|
2018-01-14 09:24:46 +01:00
|
|
|
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
|
2017-08-17 08:57:47 +02:00
|
|
|
mock_response = mock.Mock()
|
|
|
|
mock_response.status_code = 200
|
|
|
|
request.return_value = mock_response
|
|
|
|
NotifyPaymentsCommand().handle()
|
|
|
|
url = request.call_args[0][1]
|
|
|
|
assert url.startswith('http://example.org/testitem/jump/trigger/paid')
|
|
|
|
assert BasketItem.objects.get(id=item.id).payment_date
|
|
|
|
assert BasketItem.objects.get(id=item.id).notification_date
|