Coverage for website/payments/tests/test_admin_views.py: 100.00%

319 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2025-08-14 10:31 +0000

1from unittest import mock 

2from unittest.mock import MagicMock, Mock, PropertyMock, patch 

3 

4from django.apps import apps 

5from django.contrib.admin.utils import model_ngettext 

6from django.contrib.auth.models import Permission 

7from django.contrib.contenttypes.models import ContentType 

8from django.test import Client, TestCase, override_settings 

9from django.utils import timezone 

10from django.utils.translation import gettext_lazy as _ 

11 

12from freezegun import freeze_time 

13 

14from members.models import Member, Profile 

15from payments import admin_views 

16from payments.models import BankAccount, Batch, Payment, PaymentUser 

17from payments.payables import payables 

18from payments.tests.__mocks__ import MockModel 

19from payments.tests.test_services import MockPayable 

20 

21 

22@override_settings(SUSPEND_SIGNALS=True) 

23class PaymentAdminViewTest(TestCase): 

24 @classmethod 

25 def setUpTestData(cls): 

26 cls.user = Member.objects.create( 

27 username="test1", 

28 first_name="Test1", 

29 last_name="Example", 

30 email="test1@example.org", 

31 ) 

32 Profile.objects.create( 

33 user=cls.user, 

34 ) 

35 cls.user = PaymentUser.objects.get(pk=cls.user.pk) 

36 cls.payment = Payment.objects.create( 

37 amount=7.5, processed_by=cls.user, paid_by=cls.user, type=Payment.CARD 

38 ) 

39 

40 def setUp(self): 

41 payables.register(MockModel, MockPayable) 

42 self.client = Client() 

43 self.client.force_login(self.user) 

44 self.view = admin_views.PaymentAdminView() 

45 

46 def tearDown(self): 

47 payables._unregister(MockModel) 

48 

49 def _give_user_permissions(self): 

50 content_type = ContentType.objects.get_for_model(Payment) 

51 permissions = Permission.objects.filter( 

52 content_type__app_label=content_type.app_label, 

53 ) 

54 for p in permissions: 

55 self.user.user_permissions.add(p) 

56 self.user.is_staff = True 

57 self.user.save() 

58 

59 self.client.logout() 

60 self.client.force_login(self.user) 

61 

62 def test_redirect_without_permissions(self): 

63 url = "/admin/payments/payment/app_label/model/pk/create/" 

64 response = self.client.post( 

65 url, 

66 { 

67 "type": "cash_payment", 

68 }, 

69 ) 

70 self.assertEqual(response.status_code, 302) 

71 self.assertURLEqual(response.url, f"/admin/login/?next={url}") 

72 

73 @mock.patch("django.contrib.messages.error") 

74 @mock.patch("django.contrib.messages.success") 

75 @mock.patch("django.shortcuts.resolve_url") 

76 @mock.patch("payments.services.create_payment") 

77 @mock.patch("payments.payables.payables.get_payable") 

78 def test_post( 

79 self, get_payable, create_payment, resolve_url, messages_success, messages_error 

80 ): 

81 url = "/admin/payments/payment/mock_label/model/pk/create/" 

82 self._give_user_permissions() 

83 payable = MockPayable(MockModel(payer=self.user)) 

84 

85 original_get_model = apps.get_model 

86 mock_get_model = MagicMock() 

87 

88 def side_effect(*args, **kwargs): 

89 if "app_label" in kwargs and kwargs["app_label"] == "mock_label": 

90 return mock_get_model 

91 return original_get_model(*args, **kwargs) 

92 

93 apps.get_model = Mock(side_effect=side_effect) 

94 get_payable.return_value = payable 

95 create_payment.return_value = self.payment 

96 resolve_url.return_value = "/resolved_url" 

97 

98 with self.subTest("Send post without payload"): 

99 response = self.client.post(url) 

100 

101 self.assertEqual(response.status_code, 400) 

102 

103 create_payment.assert_not_called() 

104 messages_error.assert_not_called() 

105 messages_success.assert_not_called() 

106 

107 with self.subTest("Send post with successful processing, no next"): 

108 payment_type = "cash_payment" 

109 response = self.client.post( 

110 url, 

111 { 

112 "type": payment_type, 

113 }, 

114 ) 

115 

116 self.assertEqual(response.status_code, 302) 

117 self.assertEqual(response.url, "/resolved_url") 

118 

119 create_payment.assert_called_once_with(payable, self.user, payment_type) 

120 resolve_url.assert_called_once_with( 

121 "admin:payments_payment_change", self.payment.pk 

122 ) 

123 

124 messages_success.assert_called_once_with( 

125 response.wsgi_request, "Successfully paid MockPayable." 

126 ) 

127 

128 create_payment.reset_mock() 

129 messages_success.reset_mock() 

130 resolve_url.reset_mock() 

131 

132 with self.subTest("Send post with successful processing and next"): 

133 payment_type = "cash_payment" 

134 response = self.client.post( 

135 url, 

136 {"type": payment_type, "next": "/admin/events/"}, 

137 ) 

138 

139 self.assertEqual(response.status_code, 302) 

140 self.assertEqual(response.url, "/resolved_url") 

141 

142 create_payment.assert_called_once_with(payable, self.user, payment_type) 

143 resolve_url.assert_called_once_with("/admin/events/") 

144 

145 messages_success.assert_called_once_with( 

146 response.wsgi_request, 

147 "Successfully paid MockPayable.", 

148 ) 

149 

150 create_payment.reset_mock() 

151 messages_success.reset_mock() 

152 resolve_url.reset_mock() 

153 

154 with self.subTest("Send post with insecure next"): 

155 response = self.client.post( 

156 url, 

157 {"type": "cash_payment", "next": "https://ru.nl/"}, 

158 ) 

159 

160 self.assertEqual(response.status_code, 400) 

161 

162 create_payment.assert_not_called() 

163 messages_error.assert_not_called() 

164 messages_success.assert_not_called() 

165 

166 with self.subTest("Send post without permission to process the payment"): 

167 payable.model.can_manage = False 

168 response = self.client.post( 

169 url, 

170 { 

171 "type": payment_type, 

172 }, 

173 follow=True, 

174 ) 

175 self.assertEqual(response.status_code, 403) 

176 payable.model.can_manage = True 

177 

178 with self.subTest("Send post with failed processing"): 

179 create_payment.return_value = None 

180 response = self.client.post( 

181 url, 

182 { 

183 "type": payment_type, 

184 }, 

185 ) 

186 

187 messages_error.assert_called_once_with( 

188 response.wsgi_request, 

189 "Could not pay MockPayable.", 

190 ) 

191 

192 with self.subTest("Send post with exception during processing"): 

193 create_payment.side_effect = Exception("A test exception was thrown.") 

194 response = self.client.post( 

195 url, 

196 { 

197 "type": payment_type, 

198 }, 

199 ) 

200 

201 messages_error.assert_called_with( 

202 response.wsgi_request, 

203 "Something went wrong paying MockPayable: A test exception was thrown.", 

204 ) 

205 

206 

207@override_settings(SUSPEND_SIGNALS=True, THALIA_PAY_ENABLED_PAYMENT_METHOD=True) 

208@patch("payments.models.PaymentUser.tpay_allowed", PropertyMock, True) 

209class BatchProcessAdminViewTest(TestCase): 

210 fixtures = ["members.json", "bank_accounts.json"] 

211 

212 @classmethod 

213 @patch("payments.models.PaymentUser.tpay_allowed", PropertyMock, True) 

214 def setUpTestData(cls): 

215 cls.batch = Batch.objects.create() 

216 cls.user = PaymentUser.objects.get(pk=2) 

217 Payment.objects.create( 

218 amount=99, 

219 paid_by=cls.user, 

220 processed_by=cls.user, 

221 batch=cls.batch, 

222 type=Payment.TPAY, 

223 ) 

224 

225 def setUp(self): 

226 self.client = Client() 

227 self.client.force_login(self.user) 

228 self.view = admin_views.PaymentAdminView() 

229 

230 def _give_user_permissions(self): 

231 content_type = ContentType.objects.get_for_model(Batch) 

232 permissions = Permission.objects.filter( 

233 content_type__app_label=content_type.app_label, 

234 ) 

235 for p in permissions: 

236 self.user.user_permissions.add(p) 

237 self.user.is_staff = True 

238 self.user.save() 

239 

240 self.client.logout() 

241 self.client.force_login(self.user) 

242 

243 def test_permissions(self): 

244 url = f"/admin/payments/batch/{self.batch.id}/process/" 

245 response = self.client.post(url) 

246 self.assertEqual(response.status_code, 302) 

247 self.assertEqual(response.url, f"/user/account/login/?next={url}") 

248 

249 self._give_user_permissions() 

250 

251 response = self.client.post(url, follow=True) 

252 self.assertRedirects(response, f"/admin/payments/batch/{self.batch.id}/change/") 

253 

254 def test_next_validation(self): 

255 self._give_user_permissions() 

256 

257 response = self.client.post( 

258 f"/admin/payments/batch/{self.batch.id}/process/", 

259 {"next": "https://google.com"}, 

260 ) 

261 

262 self.assertEqual(response.status_code, 400) 

263 

264 @mock.patch("django.contrib.messages.error") 

265 @mock.patch("django.contrib.messages.success") 

266 def test_post(self, message_success, message_error): 

267 self._give_user_permissions() 

268 

269 response = self.client.post( 

270 f"/admin/payments/batch/{self.batch.id}/process/", 

271 {"next": "/admin/events/"}, 

272 ) 

273 

274 self.assertEqual(response.status_code, 302) 

275 self.assertEqual(response.url, "/admin/events/") 

276 

277 self.assertEqual(Batch.objects.get(id=self.batch.id).processed, True) 

278 

279 message_success.assert_called_once_with( 

280 response.wsgi_request, 

281 _("Successfully processed {}.").format(model_ngettext(self.batch, 1)), 

282 ) 

283 

284 response = self.client.post(f"/admin/payments/batch/{self.batch.id}/process/") 

285 

286 self.assertEqual(Batch.objects.get(id=self.batch.id).processed, True) 

287 

288 message_error.assert_called_once_with( 

289 response.wsgi_request, 

290 _("{} already processed.").format(model_ngettext(self.batch, 1)), 

291 ) 

292 

293 

294@override_settings(SUSPEND_SIGNALS=True) 

295@freeze_time("2020-01-01") 

296class BatchExportAdminViewTest(TestCase): 

297 @classmethod 

298 def setUpTestData(cls): 

299 cls.batch = Batch.objects.create() 

300 cls.user = Member.objects.create( 

301 username="test1", 

302 first_name="Test1", 

303 last_name="Example", 

304 email="test1@example.org", 

305 ) 

306 Profile.objects.create(user=cls.user) 

307 cls.user = PaymentUser.objects.get(pk=cls.user.pk) 

308 

309 def setUp(self): 

310 self.client = Client() 

311 self.client.force_login(self.user) 

312 self.view = admin_views.BatchExportAdminView() 

313 

314 def _give_user_permissions(self): 

315 content_type = ContentType.objects.get_for_model(Batch) 

316 permissions = Permission.objects.filter( 

317 content_type__app_label=content_type.app_label, 

318 ) 

319 for p in permissions: 

320 self.user.user_permissions.add(p) 

321 self.user.is_staff = True 

322 self.user.save() 

323 

324 self.client.logout() 

325 self.client.force_login(self.user) 

326 

327 def test_permission(self): 

328 url = f"/admin/payments/batch/{self.batch.id}/export/" 

329 response = self.client.post(url) 

330 self.assertEqual(response.status_code, 302) 

331 self.assertURLEqual(response.url, f"/admin/login/?next={url}") 

332 

333 self._give_user_permissions() 

334 

335 response = self.client.post(url, follow=True) 

336 self.assertEqual(response.status_code, 200) 

337 

338 def test_post(self): 

339 self._give_user_permissions() 

340 

341 user2 = Member.objects.create( 

342 username="test2", 

343 first_name="Test2", 

344 last_name="Example", 

345 email="test1@example.org", 

346 ) 

347 Profile.objects.create(user=user2) 

348 user2 = PaymentUser.objects.get(pk=user2.pk) 

349 

350 BankAccount.objects.create( 

351 last_used=timezone.now(), 

352 owner=self.user, 

353 iban="DE75512108001245126199", 

354 mandate_no="2", 

355 valid_from=timezone.now(), 

356 initials="T.E.S.T.", 

357 last_name="ersssss", 

358 ) 

359 BankAccount.objects.create( 

360 last_used=timezone.now(), 

361 owner=user2, 

362 iban="NL02ABNA0123456789", 

363 mandate_no="1", 

364 valid_from=timezone.now(), 

365 initials="T.E.S.T.", 

366 last_name="ersssss2", 

367 ) 

368 

369 Payment.objects.bulk_create( 

370 [ 

371 Payment( 

372 amount=1, paid_by=self.user, type=Payment.TPAY, batch=self.batch 

373 ), 

374 Payment( 

375 amount=2, paid_by=self.user, type=Payment.TPAY, batch=self.batch 

376 ), 

377 Payment(amount=4, paid_by=user2, type=Payment.TPAY, batch=self.batch), 

378 Payment(amount=2, paid_by=user2, type=Payment.TPAY, batch=self.batch), 

379 ] 

380 ) 

381 

382 response = self.client.post(f"/admin/payments/batch/{self.batch.id}/export/") 

383 

384 self.assertEqual( 

385 response.content, 

386 b"Account holder,IBAN,Mandate Reference,Amount,Description,Mandate Date\r\n" 

387 b"T.E.S.T. ersssss,DE75512108001245126199,2,3.00,Thalia Pay payments for 2020-1,2020-01-01\r\n" 

388 b"T.E.S.T. ersssss2,NL02ABNA0123456789,1,6.00,Thalia Pay payments for 2020-1,2020-01-01\r\n", 

389 ) 

390 

391 

392@override_settings(SUSPEND_SIGNALS=True) 

393@freeze_time("2020-01-01") 

394class BatchTopicExportAdminViewTest(TestCase): 

395 @classmethod 

396 def setUpTestData(cls): 

397 cls.batch = Batch.objects.create() 

398 cls.user = Member.objects.create( 

399 username="test1", 

400 first_name="Test1", 

401 last_name="Example", 

402 email="test1@example.org", 

403 ) 

404 Profile.objects.create(user=cls.user) 

405 cls.user = PaymentUser.objects.get(pk=cls.user.pk) 

406 

407 def setUp(self): 

408 self.client = Client() 

409 self.client.force_login(self.user) 

410 self.view = admin_views.BatchTopicExportAdminView() 

411 

412 def _give_user_permissions(self): 

413 content_type = ContentType.objects.get_for_model(Batch) 

414 permissions = Permission.objects.filter( 

415 content_type__app_label=content_type.app_label, 

416 ) 

417 for p in permissions: 

418 self.user.user_permissions.add(p) 

419 self.user.is_staff = True 

420 self.user.save() 

421 

422 self.client.logout() 

423 self.client.force_login(self.user) 

424 

425 def test_permission(self): 

426 url = f"/admin/payments/batch/{self.batch.id}/export-topic/" 

427 response = self.client.post(url) 

428 self.assertEqual(response.status_code, 302) 

429 self.assertURLEqual(response.url, f"/admin/login/?next={url}") 

430 

431 self._give_user_permissions() 

432 

433 response = self.client.post(url) 

434 self.assertEqual(response.status_code, 200) 

435 

436 def test_post(self): 

437 self._give_user_permissions() 

438 

439 user2 = Member.objects.create( 

440 username="test2", 

441 first_name="Test2", 

442 last_name="Example", 

443 email="test1@example.org", 

444 ) 

445 Profile.objects.create(user=user2) 

446 user2 = PaymentUser.objects.get(pk=user2.pk) 

447 

448 BankAccount.objects.create( 

449 last_used=timezone.now(), 

450 owner=self.user, 

451 iban="DE75512108001245126199", 

452 mandate_no="2", 

453 valid_from=timezone.now(), 

454 ) 

455 BankAccount.objects.create( 

456 last_used=timezone.now(), 

457 owner=user2, 

458 iban="NL02ABNA0123456789", 

459 mandate_no="1", 

460 valid_from=timezone.now(), 

461 ) 

462 

463 Payment.objects.bulk_create( 

464 [ 

465 Payment( 

466 amount=1, 

467 paid_by=self.user, 

468 type=Payment.TPAY, 

469 batch=self.batch, 

470 topic="test1", 

471 ), 

472 Payment( 

473 amount=2, 

474 paid_by=self.user, 

475 type=Payment.TPAY, 

476 batch=self.batch, 

477 topic="test2", 

478 ), 

479 Payment( 

480 amount=4, 

481 paid_by=user2, 

482 type=Payment.TPAY, 

483 batch=self.batch, 

484 topic="test1", 

485 ), 

486 Payment( 

487 amount=2, 

488 paid_by=user2, 

489 type=Payment.TPAY, 

490 batch=self.batch, 

491 topic="test2", 

492 ), 

493 ] 

494 ) 

495 

496 response = self.client.post( 

497 f"/admin/payments/batch/{self.batch.id}/export-topic/" 

498 ) 

499 

500 self.assertEqual( 

501 response.content, 

502 b"Topic,No. of payments,First payment,Last payment,Total amount\r\n" 

503 b"test1,2,2020-01-01,2020-01-01,5.00\r\n" 

504 b"test2,2,2020-01-01,2020-01-01,4.00\r\n", 

505 ) 

506 

507 

508@override_settings(SUSPEND_SIGNALS=True) 

509@freeze_time("2020-01-01") 

510class BatchTopicDescriptionAdminViewTest(TestCase): 

511 @classmethod 

512 def setUpTestData(cls): 

513 cls.batch = Batch.objects.create() 

514 cls.user = Member.objects.create( 

515 username="test1", 

516 first_name="Test1", 

517 last_name="Example", 

518 email="test1@example.org", 

519 ) 

520 Profile.objects.create(user=cls.user) 

521 

522 def setUp(self): 

523 self.client = Client() 

524 self.client.force_login(self.user) 

525 self.view = admin_views.BatchTopicDescriptionAdminView() 

526 

527 def _give_user_permissions(self): 

528 content_type = ContentType.objects.get_for_model(Batch) 

529 permissions = Permission.objects.filter( 

530 content_type__app_label=content_type.app_label, 

531 ) 

532 for p in permissions: 

533 self.user.user_permissions.add(p) 

534 self.user.is_staff = True 

535 self.user.save() 

536 

537 self.client.logout() 

538 self.client.force_login(self.user) 

539 

540 def test_permission(self): 

541 url = f"/admin/payments/batch/{self.batch.id}/topic-description/" 

542 response = self.client.post(url) 

543 self.assertEqual(response.status_code, 302) 

544 self.assertURLEqual(response.url, f"/admin/login/?next={url}") 

545 

546 self._give_user_permissions() 

547 

548 response = self.client.post(url) 

549 self.assertEqual(response.status_code, 200) 

550 

551 def test_post(self): 

552 self._give_user_permissions() 

553 

554 self.user2 = Member.objects.create( 

555 username="test2", 

556 first_name="Test2", 

557 last_name="Example", 

558 email="test1@example.org", 

559 ) 

560 Profile.objects.create(user=self.user2) 

561 

562 BankAccount.objects.create( 

563 last_used=timezone.now(), 

564 owner=self.user, 

565 iban="DE75512108001245126199", 

566 mandate_no="2", 

567 valid_from=timezone.now(), 

568 ) 

569 BankAccount.objects.create( 

570 last_used=timezone.now(), 

571 owner=self.user2, 

572 iban="NL02ABNA0123456789", 

573 mandate_no="1", 

574 valid_from=timezone.now(), 

575 ) 

576 

577 Payment.objects.bulk_create( 

578 [ 

579 Payment( 

580 amount=1, 

581 paid_by=self.user, 

582 type=Payment.TPAY, 

583 batch=self.batch, 

584 topic="test1", 

585 ), 

586 Payment( 

587 amount=2, 

588 paid_by=self.user, 

589 type=Payment.TPAY, 

590 batch=self.batch, 

591 topic="test2", 

592 ), 

593 Payment( 

594 amount=4, 

595 paid_by=self.user2, 

596 type=Payment.TPAY, 

597 batch=self.batch, 

598 topic="test1", 

599 ), 

600 Payment( 

601 amount=2, 

602 paid_by=self.user2, 

603 type=Payment.TPAY, 

604 batch=self.batch, 

605 topic="test2", 

606 ), 

607 ] 

608 ) 

609 

610 response = self.client.post( 

611 f"/admin/payments/batch/{self.batch.id}/topic-description/" 

612 ) 

613 

614 self.assertContains( 

615 response, 

616 "- test1 (2x) [2020-01-01 -- 2020-01-01], total €5.00\n- test2 (2x) [2020-01-01 -- 2020-01-01], total €4.00\n", 

617 ) 

618 

619 

620@override_settings(SUSPEND_SIGNALS=True) 

621class BatchNewFilledAdminViewTest(TestCase): 

622 @classmethod 

623 def setUpTestData(cls): 

624 cls.batch = Batch.objects.create() 

625 cls.user = Member.objects.create( 

626 username="test1", 

627 first_name="Test1", 

628 last_name="Example", 

629 email="test1@example.org", 

630 ) 

631 Profile.objects.create(user=cls.user) 

632 cls.user = PaymentUser.objects.get(pk=cls.user.pk) 

633 

634 def setUp(self): 

635 self.client = Client() 

636 self.client.force_login(self.user) 

637 self.view = admin_views.BatchExportAdminView() 

638 

639 def _give_user_permissions(self): 

640 content_type = ContentType.objects.get_for_model(Batch) 

641 permissions = Permission.objects.filter( 

642 content_type__app_label=content_type.app_label, 

643 ) 

644 for p in permissions: 

645 self.user.user_permissions.add(p) 

646 self.user.is_staff = True 

647 self.user.save() 

648 

649 self.client.logout() 

650 self.client.force_login(self.user) 

651 

652 def test_permission(self): 

653 url = "/admin/payments/batch/new_filled/" 

654 response = self.client.post(url) 

655 self.assertEqual(response.status_code, 302) 

656 self.assertURLEqual(response.url, f"/admin/login/?next={url}") 

657 

658 self._give_user_permissions() 

659 

660 response = self.client.post(url) 

661 

662 b = Batch.objects.exclude(id=self.batch.id).first() 

663 self.assertRedirects(response, f"/admin/payments/batch/{b.id}/change/") 

664 

665 @freeze_time("2020-03-01") 

666 def test_post(self): 

667 self._give_user_permissions() 

668 

669 Payment.objects.bulk_create( 

670 [ 

671 Payment( 

672 amount=1, 

673 type=Payment.TPAY, 

674 created_at=timezone.datetime( 

675 2020, 1, 31, tzinfo=timezone.timezone.utc 

676 ), 

677 ), 

678 Payment( 

679 amount=2, 

680 type=Payment.TPAY, 

681 created_at=timezone.datetime( 

682 2020, 2, 1, tzinfo=timezone.timezone.utc 

683 ), 

684 ), 

685 Payment( 

686 amount=3, 

687 type=Payment.TPAY, 

688 created_at=timezone.datetime( 

689 2020, 2, 10, tzinfo=timezone.timezone.utc 

690 ), 

691 batch=self.batch, 

692 ), 

693 Payment( 

694 amount=4, 

695 type=Payment.TPAY, 

696 created_at=timezone.datetime( 

697 2020, 2, 28, tzinfo=timezone.timezone.utc 

698 ), 

699 ), 

700 Payment( 

701 amount=5, 

702 type=Payment.TPAY, 

703 created_at=timezone.datetime( 

704 2020, 2, 29, tzinfo=timezone.timezone.utc 

705 ), 

706 ), 

707 Payment( 

708 amount=6, 

709 type=Payment.TPAY, 

710 created_at=timezone.datetime( 

711 2020, 3, 1, tzinfo=timezone.timezone.utc 

712 ), 

713 ), 

714 Payment( 

715 amount=7, 

716 type=Payment.WIRE, 

717 created_at=timezone.datetime( 

718 2020, 1, 1, tzinfo=timezone.timezone.utc 

719 ), 

720 ), 

721 ] 

722 ) 

723 

724 self.client.post("/admin/payments/batch/new_filled/") 

725 

726 b = Batch.objects.exclude(id=self.batch.id).first() 

727 

728 self.assertEqual(Payment.objects.get(amount=1).batch.id, b.id) 

729 self.assertEqual(Payment.objects.get(amount=2).batch.id, b.id) 

730 self.assertEqual(Payment.objects.get(amount=3).batch.id, self.batch.id) 

731 self.assertEqual(Payment.objects.get(amount=4).batch.id, b.id) 

732 self.assertEqual(Payment.objects.get(amount=5).batch.id, b.id) 

733 self.assertEqual(Payment.objects.get(amount=6).batch.id, b.id) 

734 self.assertIsNone(Payment.objects.get(amount=7).batch)