Projet

Général

Profil

0001-lingo-add-API-endpoint-to-cancel-a-basket-item-9794.patch

Frédéric Péters, 26 mai 2016 19:35

Télécharger (7,59 ko)

Voir les différences:

Subject: [PATCH] lingo: add API endpoint to cancel a basket item (#9794)

 combo/apps/lingo/models.py  |  5 +++--
 combo/apps/lingo/urls.py    |  5 ++++-
 combo/apps/lingo/views.py   | 42 ++++++++++++++++++++++++++++++++++++++++++
 tests/test_lingo_payment.py | 31 ++++++++++++++++++++++++++++---
 4 files changed, 77 insertions(+), 6 deletions(-)
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
-