0001-lingo-add-API-endpoint-to-cancel-a-basket-item-9794.patch
combo/apps/lingo/models.py | ||
---|---|---|
216 | 216 |
self.notification_date = timezone.now() |
217 | 217 |
self.save() |
218 | 218 | |
219 |
def notify_cancellation(self): |
|
220 |
self.notify('cancelled') |
|
219 |
def notify_cancellation(self, skip_notification=False): |
|
220 |
if not skip_notification: |
|
221 |
self.notify('cancelled') |
|
221 | 222 |
self.cancellation_date = timezone.now() |
222 | 223 |
self.save() |
223 | 224 |
combo/apps/lingo/urls.py | ||
---|---|---|
19 | 19 |
from combo.urls_utils import decorated_includes, manager_required |
20 | 20 | |
21 | 21 |
from .views import (RegiesApiView, AddBasketItemApiView, PayView, CallbackView, |
22 |
ReturnView, ItemDownloadView, ItemView, CancelItemView) |
|
22 |
ReturnView, ItemDownloadView, ItemView, CancelItemView, |
|
23 |
RemoveBasketItemApiView) |
|
23 | 24 |
from .manager_views import (RegieListView, RegieCreateView, RegieUpdateView, |
24 | 25 |
RegieDeleteView, TransactionListView, ManagerHomeView) |
25 | 26 | |
... | ... | |
38 | 39 |
url('^api/lingo/regies$', RegiesApiView.as_view(), name='api-regies'), |
39 | 40 |
url('^api/lingo/add-basket-item$', AddBasketItemApiView.as_view(), |
40 | 41 |
name='api-add-basket-item'), |
42 |
url('^api/lingo/remove-basket-item$', RemoveBasketItemApiView.as_view(), |
|
43 |
name='api-remove-basket-item'), |
|
41 | 44 |
url(r'^lingo/pay$', PayView.as_view(), name='lingo-pay'), |
42 | 45 |
url(r'^lingo/cancel/(?P<pk>\w+)/$', CancelItemView.as_view(), name='lingo-cancel-item'), |
43 | 46 |
url(r'^lingo/callback/(?P<regie_pk>\w+)/$', CallbackView.as_view(), name='lingo-callback'), |
combo/apps/lingo/views.py | ||
---|---|---|
136 | 136 |
item.save() |
137 | 137 | |
138 | 138 |
response = HttpResponse(content_type='application/json') |
139 |
response.write(json.dumps({'result': 'success', 'id': str(item.id)})) |
|
140 |
return response |
|
141 | ||
142 | ||
143 |
class RemoveBasketItemApiView(View): |
|
144 |
http_method_names = ['post', 'options'] |
|
145 | ||
146 |
@csrf_exempt |
|
147 |
def dispatch(self, *args, **kwargs): |
|
148 |
return super(RemoveBasketItemApiView, self).dispatch(*args, **kwargs) |
|
149 | ||
150 |
def post(self, request, *args, **kwargs): |
|
151 |
key = getattr(settings, 'LINGO_API_SIGN_KEY', '12345') |
|
152 |
if not check_query(request.META['QUERY_STRING'], key): |
|
153 |
return HttpResponseForbidden() |
|
154 | ||
155 |
request_body = json.loads(self.request.body) |
|
156 | ||
157 |
if not 'basket_item_id' in request_body: |
|
158 |
raise Exception('missing basket_item_id parameter') |
|
159 | ||
160 |
try: |
|
161 |
if request.GET.get('NameId'): |
|
162 |
if UserSAMLIdentifier is None: |
|
163 |
raise Exception('missing mellon?') |
|
164 |
try: |
|
165 |
user = UserSAMLIdentifier.objects.get(name_id=request.GET.get('NameId')).user |
|
166 |
except UserSAMLIdentifier.DoesNotExist: |
|
167 |
raise Exception('unknown name id') |
|
168 |
elif request.GET.get('email'): |
|
169 |
user = User.objects.get(email=request.GET.get('email')) |
|
170 |
else: |
|
171 |
raise Exception('no user specified') |
|
172 |
except User.DoesNotExist: |
|
173 |
raise Exception('unknown user') |
|
174 | ||
175 |
item = BasketItem.objects.get(id=request_body.get('basket_item_id'), |
|
176 |
user=user, cancellation_date__isnull=True) |
|
177 |
item.notify_cancellation(skip_notification=bool(request_body.get('skip_notification'))) |
|
178 | ||
179 |
response = HttpResponse(content_type='application/json') |
|
139 | 180 |
response.write(json.dumps({'result': 'success'})) |
140 | 181 |
return response |
141 | 182 | |
183 | ||
142 | 184 |
class PayView(View): |
143 | 185 |
def post(self, request, *args, **kwargs): |
144 | 186 |
regie_id = request.POST.get('regie') |
tests/test_lingo_payment.py | ||
---|---|---|
102 | 102 |
url = sign_url(url, settings.LINGO_API_SIGN_KEY) |
103 | 103 |
resp = client.post(url, json.dumps(data), content_type='application/json') |
104 | 104 |
assert resp.status_code == 200 |
105 |
assert json.loads(resp.content) == {'result': 'success'}
|
|
105 |
assert json.loads(resp.content)['result'] == 'success'
|
|
106 | 106 |
assert BasketItem.objects.filter(amount=amount).exists() |
107 | 107 | |
108 | 108 |
data['extra'] = {'amount': '22.22'} |
109 | 109 |
url = sign_url(url, settings.LINGO_API_SIGN_KEY) |
110 | 110 |
resp = client.post(url, json.dumps(data), content_type='application/json') |
111 | 111 |
assert resp.status_code == 200 |
112 |
assert json.loads(resp.content) == {'result': 'success'}
|
|
112 |
assert json.loads(resp.content)['result'] == 'success'
|
|
113 | 113 |
assert BasketItem.objects.filter(amount=Decimal('64.22')).exists() |
114 | 114 | |
115 | 115 |
data['amount'] = [amount] |
... | ... | |
117 | 117 |
resp = client.post('%s&amount=5' % url, json.dumps(data), |
118 | 118 |
content_type='application/json') |
119 | 119 |
assert resp.status_code == 200 |
120 |
assert json.loads(resp.content) == {'result': 'success'}
|
|
120 |
assert json.loads(resp.content)['result'] == 'success'
|
|
121 | 121 |
assert BasketItem.objects.filter(amount=Decimal('81.22')).exists() |
122 | 122 | |
123 |
def test_cancel_basket_item(regie, user): |
|
124 |
user_email = 'foo@example.com' |
|
125 |
User.objects.get_or_create(email=user_email) |
|
126 |
url = '%s?email=%s' % (reverse('api-add-basket-item'), user_email) |
|
127 |
url = sign_url(url, settings.LINGO_API_SIGN_KEY) |
|
128 |
data = {'amount': 42, 'display_name': 'test amount', 'url': 'http://example.com'} |
|
129 |
resp = client.post(url, json.dumps(data), content_type='application/json') |
|
130 |
assert resp.status_code == 200 |
|
131 |
assert json.loads(resp.content)['result'] == 'success' |
|
132 |
assert BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists() |
|
133 |
basket_item_id = json.loads(resp.content)['id'] |
|
134 | ||
135 |
data = {'amount': 21, 'display_name': 'test amount', 'url': 'http://example.com'} |
|
136 |
resp = client.post(url, json.dumps(data), content_type='application/json') |
|
137 |
assert resp.status_code == 200 |
|
138 |
assert json.loads(resp.content)['result'] == 'success' |
|
139 |
assert BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists() |
|
140 |
assert BasketItem.objects.filter(amount=21, cancellation_date__isnull=True).exists() |
|
141 | ||
142 |
url = '%s?email=%s' % (reverse('api-remove-basket-item'), user_email) |
|
143 |
url = sign_url(url, settings.LINGO_API_SIGN_KEY) |
|
144 |
data = {'basket_item_id': basket_item_id, 'skip_notification': True} |
|
145 |
resp = client.post(url, json.dumps(data), content_type='application/json') |
|
146 |
assert not BasketItem.objects.filter(amount=42, cancellation_date__isnull=True).exists() |
|
147 |
assert BasketItem.objects.filter(amount=21, cancellation_date__isnull=True).exists() |
|
123 | 148 | |
124 | 149 |
def test_payment_callback(regie, user): |
125 | 150 |
item = BasketItem.objects.create(user=user, regie=regie, |
126 |
- |