1
1
from __future__ import annotations
2
2
3
3
import json
4
+ from copy import deepcopy
4
5
from datetime import date
5
6
from decimal import Decimal
6
7
from unittest import TestCase
33
34
}
34
35
35
36
37
+ class PaymentQuerySet (Mock ):
38
+ __payments = {}
39
+
40
+ def create (self , ** kwargs ):
41
+ if kwargs :
42
+ raise NotImplementedError (f"arguments not supported yet: { kwargs } " )
43
+ id_ = max (self .__payments ) + 1 if self .__payments else 1
44
+ self .__payments [id_ ] = {}
45
+ payment = Payment ()
46
+ payment .id = id_
47
+ payment .save ()
48
+ return payment
49
+
50
+ def get (self , * args , ** kwargs ):
51
+ if args or kwargs :
52
+ return self .filter (* args , ** kwargs ).get ()
53
+ payment = Payment ()
54
+ (payment_fields ,) = self .__payments .values ()
55
+ for payment_field_name , payment_field_value in payment_fields .items ():
56
+ setattr (payment , payment_field_name , deepcopy (payment_field_value ))
57
+ return payment
58
+
59
+ def filter (self , * args , pk = None , ** kwargs ):
60
+ if args or kwargs :
61
+ raise NotImplementedError (f"arguments not supported yet: { args } , { kwargs } " )
62
+ if pk is not None :
63
+ return PaymentQuerySet (
64
+ {pk_ : payment for pk_ , payment in self .__payments .items () if pk_ == pk }
65
+ )
66
+ return self
67
+
68
+ def update (self , ** kwargs ):
69
+ for payment in self .__payments .values ():
70
+ for field_name , field_value in kwargs .items ():
71
+ if not any (
72
+ field .name == field_name
73
+ for field in Payment ._meta .get_fields (
74
+ include_parents = True , include_hidden = True
75
+ )
76
+ ):
77
+ raise NotImplementedError (
78
+ f"updating unknown field not supported yet: { field_name } "
79
+ )
80
+ payment [field_name ] = deepcopy (field_value )
81
+
82
+ def delete (self ):
83
+ self .__payments .clear ()
84
+
85
+
36
86
class Payment (Mock ):
87
+ objects = PaymentQuerySet ()
88
+
37
89
id = 1
38
90
description = "payment"
39
91
currency = "USD"
@@ -57,9 +109,14 @@ class Payment(Mock):
57
109
}
58
110
)
59
111
112
+ @property
113
+ def pk (self ):
114
+ return self .id
115
+
60
116
def change_status (self , status , message = "" ):
61
117
self .status = status
62
118
self .message = message
119
+ self .save (update_fields = ["status" , "message" ])
63
120
64
121
def get_failure_url (self ):
65
122
return "http://cancel.com"
@@ -77,10 +134,58 @@ def get_purchased_items(self):
77
134
def get_success_url (self ):
78
135
return "http://success.com"
79
136
137
+ def save (self , * args , update_fields = None , ** kwargs ):
138
+ if args or kwargs :
139
+ raise NotImplementedError (f"arguments not supported yet: { args } , { kwargs } " )
140
+ if update_fields is None :
141
+ update_fields = {
142
+ field .name
143
+ for field in self ._meta .get_fields (
144
+ include_parents = True , include_hidden = True
145
+ )
146
+ }
147
+ Payment .objects .filter (pk = self .pk ).update (
148
+ ** {field : getattr (self , field ) for field in update_fields }
149
+ )
150
+
151
+ def refresh_from_db (self , * args , ** kwargs ):
152
+ if args or kwargs :
153
+ raise NotImplementedError (f"arguments not supported yet: { args } , { kwargs } " )
154
+ payment_from_db = Payment .objects .get (pk = self .pk )
155
+ for field in self ._meta .get_fields (include_parents = True , include_hidden = True ):
156
+ field_value_from_db = getattr (payment_from_db , field .name )
157
+ setattr (self , field .name , field_value_from_db )
158
+
159
+ class Meta (Mock ):
160
+ def get_fields (self , include_parents = True , include_hidden = False ):
161
+ fields = []
162
+ for field_name in {
163
+ "id" ,
164
+ "description" ,
165
+ "currency" ,
166
+ "delivery" ,
167
+ "status" ,
168
+ "tax" ,
169
+ "token" ,
170
+ "total" ,
171
+ "captured_amount" ,
172
+ "variant" ,
173
+ "transaction_id" ,
174
+ "message" ,
175
+ "extra_data" ,
176
+ }:
177
+ field = Mock ()
178
+ field .name = field_name
179
+ fields .append (field )
180
+ return tuple (fields )
181
+
182
+ _meta = Meta ()
183
+
80
184
81
185
class TestPaypalProvider (TestCase ):
82
186
def setUp (self ):
83
- self .payment = Payment ()
187
+ Payment .objects .delete ()
188
+ self .payment = Payment .objects .create ()
84
189
self .provider = PaypalProvider (secret = SECRET , client_id = CLIENT_ID )
85
190
86
191
def test_provider_raises_redirect_needed_on_success (self ):
@@ -171,6 +276,9 @@ def test_provider_redirects_on_success_captured_payment(
171
276
172
277
self .assertEqual (self .payment .status , PaymentStatus .CONFIRMED )
173
278
self .assertEqual (self .payment .captured_amount , self .payment .total )
279
+ self .payment .refresh_from_db ()
280
+ self .assertEqual (self .payment .status , PaymentStatus .CONFIRMED )
281
+ self .assertEqual (self .payment .captured_amount , self .payment .total )
174
282
175
283
@patch ("requests.post" )
176
284
@patch ("payments.paypal.redirect" )
@@ -202,6 +310,9 @@ def test_provider_redirects_on_success_preauth_payment(
202
310
203
311
self .assertEqual (self .payment .status , PaymentStatus .PREAUTH )
204
312
self .assertEqual (self .payment .captured_amount , Decimal ("0" ))
313
+ self .payment .refresh_from_db ()
314
+ self .assertEqual (self .payment .status , PaymentStatus .PREAUTH )
315
+ self .assertEqual (self .payment .captured_amount , Decimal ("0" ))
205
316
206
317
@patch ("payments.paypal.redirect" )
207
318
def test_provider_request_without_payerid_redirects_on_failure (
@@ -211,6 +322,8 @@ def test_provider_request_without_payerid_redirects_on_failure(
211
322
request .GET = {"token" : "test" , "PayerID" : None }
212
323
self .provider .process_data (self .payment , request )
213
324
self .assertEqual (self .payment .status , PaymentStatus .REJECTED )
325
+ self .payment .refresh_from_db ()
326
+ self .assertEqual (self .payment .status , PaymentStatus .REJECTED )
214
327
215
328
@patch ("requests.post" )
216
329
def test_provider_renews_access_token (self , mocked_post ):
0 commit comments