Coverage for website/registrations/tests/test_services.py: 100.00%

403 statements  

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

1from datetime import date 

2 

3from django.core import mail 

4from django.test import TestCase, override_settings 

5from django.utils import timezone 

6 

7from freezegun import freeze_time 

8 

9from members.models import Member, Membership 

10from payments.exceptions import PaymentError 

11from payments.models import BankAccount, Payment 

12from payments.services import create_payment 

13from registrations import services 

14from registrations.models import Entry, Registration, Renewal 

15 

16 

17class ServicesTest(TestCase): 

18 fixtures = ["members.json"] 

19 

20 @classmethod 

21 @freeze_time("2023-08-25") 

22 def setUpTestData(cls): 

23 cls.admin = Member.objects.get(pk=2) 

24 cls.admin.is_superuser = True 

25 cls.admin.save() 

26 

27 cls.member = Member.objects.get(pk=1) 

28 cls.member.email = "test@example.com" 

29 cls.member.save() 

30 

31 cls.membership = cls.member.membership_set.first() 

32 cls.membership.until = "2023-09-01" 

33 cls.membership.save() 

34 

35 cls.member_registration = Registration.objects.create( 

36 first_name="John", 

37 last_name="Doe", 

38 email="johndoe@example.com", 

39 programme="computingscience", 

40 student_number="s1234567", 

41 starting_year=2014, 

42 address_street="Heyendaalseweg 135", 

43 address_street2="", 

44 address_postal_code="6525AJ", 

45 address_city="Nijmegen", 

46 address_country="NL", 

47 phone_number="06123456789", 

48 birthday="1990-01-01", 

49 length=Entry.MEMBERSHIP_YEAR, 

50 contribution=7.5, 

51 membership_type=Membership.MEMBER, 

52 status=Entry.STATUS_CONFIRM, 

53 optin_thabloid=True, 

54 ) 

55 

56 cls.honory_registration = Registration.objects.create( 

57 first_name="Bobby", 

58 last_name="Bobs", 

59 email="johnnydoe@examply.com", 

60 student_number="s1234577", 

61 starting_year=2014, 

62 address_street="Heyendaalseweg 135", 

63 address_street2="", 

64 address_postal_code="6525AJ", 

65 address_city="Nijmegen", 

66 address_country="NL", 

67 phone_number="06123456799", 

68 birthday="1990-01-01", 

69 length=Entry.MEMBERSHIP_STUDY, 

70 contribution=7.5, 

71 membership_type=Membership.HONORARY, 

72 status=Entry.STATUS_CONFIRM, 

73 optin_thabloid=False, 

74 ) 

75 

76 cls.benefactor_registration = Registration.objects.create( 

77 first_name="Jane", 

78 last_name="Doe", 

79 username="janedoe", 

80 email="janedoe@example.com", 

81 student_number="s1234568", 

82 starting_year=2014, 

83 address_street="Heyendaalseweg 135", 

84 address_street2="", 

85 address_postal_code="6525AJ", 

86 address_city="Nijmegen", 

87 address_country="NL", 

88 phone_number="06123456789", 

89 birthday="1990-01-01", 

90 length=Entry.MEMBERSHIP_YEAR, 

91 contribution=7.5, 

92 membership_type=Membership.BENEFACTOR, 

93 status=Entry.STATUS_CONFIRM, 

94 optin_thabloid=False, 

95 ) 

96 

97 cls.study_time_member_registration = Registration.objects.create( 

98 first_name="Foo", 

99 last_name="Bar", 

100 email="foobar@example.com", 

101 programme="computingscience", 

102 student_number="s1234569", 

103 starting_year=2014, 

104 address_street="Heyendaalseweg 135", 

105 address_street2="", 

106 address_postal_code="6525AJ", 

107 address_city="Nijmegen", 

108 address_country="NL", 

109 phone_number="06123456789", 

110 birthday="1990-01-01", 

111 length=Entry.MEMBERSHIP_STUDY, 

112 contribution=30, 

113 membership_type=Membership.MEMBER, 

114 status=Entry.STATUS_CONFIRM, 

115 ) 

116 

117 cls.renewal = Renewal.objects.create( 

118 member=cls.member, 

119 length=Entry.MEMBERSHIP_YEAR, 

120 membership_type=Membership.MEMBER, 

121 status=Entry.STATUS_REVIEW, 

122 contribution=7.5, 

123 ) 

124 

125 def test_confirm_registration(self): 

126 with self.subTest("Member"): 

127 self.assertEqual(self.member_registration.status, Entry.STATUS_CONFIRM) 

128 services.confirm_registration(self.member_registration) 

129 self.assertEqual(self.member_registration.status, Entry.STATUS_REVIEW) 

130 self.assertEqual(len(mail.outbox), 1) # Sends an email to the board. 

131 

132 mail.outbox = [] 

133 

134 with self.subTest("Benefactor"): 

135 self.assertEqual(self.benefactor_registration.status, Entry.STATUS_CONFIRM) 

136 services.confirm_registration(self.benefactor_registration) 

137 self.assertEqual(self.benefactor_registration.status, Entry.STATUS_REVIEW) 

138 self.assertEqual( 

139 len(mail.outbox), 2 

140 ) # Also sends information about references. 

141 

142 mail.outbox = [] 

143 

144 with self.subTest("Already confirmed."): 

145 with self.assertRaises(ValueError): 

146 services.confirm_registration(self.member_registration) 

147 

148 def test_accept_registration(self): 

149 with self.subTest("Not in review."): 

150 with self.assertRaises(ValueError): 

151 services.accept_registration(self.member_registration, actor=self.admin) 

152 

153 self.member_registration.status = Entry.STATUS_REVIEW 

154 self.member_registration.save() 

155 

156 # Existing member has the default username. 

157 self.member.username = "jdoe" 

158 self.member.save() 

159 

160 with self.subTest("Username not unique"): 

161 # Raises and does not commit changes. Does not send email. 

162 with self.assertRaises(ValueError): 

163 services.accept_registration(self.member_registration, actor=self.admin) 

164 

165 self.member_registration.refresh_from_db() 

166 self.assertEqual(self.member_registration.status, Entry.STATUS_REVIEW) 

167 self.assertEqual(len(mail.outbox), 0) 

168 

169 self.member_registration.username = "johndoe" 

170 self.member_registration.save() 

171 

172 self.member.email = self.member_registration.email 

173 self.member.save() 

174 mail.outbox = [] 

175 

176 with self.subTest("Email not unique"): 

177 # Raises and does not commit changes. Does not send email. 

178 with self.assertRaises(ValueError): 

179 services.accept_registration(self.member_registration, actor=self.admin) 

180 

181 self.member_registration.refresh_from_db() 

182 self.assertEqual(self.member_registration.status, Entry.STATUS_REVIEW) 

183 self.assertEqual(len(mail.outbox), 0) 

184 

185 self.member_registration.email = "unique@example.com" 

186 self.member_registration.save() 

187 mail.outbox = [] 

188 

189 with self.subTest("Normal"): 

190 # Succeeds and sends payment email. 

191 services.accept_registration(self.member_registration, actor=self.admin) 

192 

193 self.member_registration.refresh_from_db() 

194 self.assertEqual(self.member_registration.status, Entry.STATUS_ACCEPTED) 

195 self.assertEqual(len(mail.outbox), 1) 

196 self.assertEqual( 

197 mail.outbox[0].subject, 

198 "[THALIA] Registration accepted", 

199 ) 

200 

201 services.revert_registration(self.member_registration, actor=self.admin) 

202 

203 self.member_registration.direct_debit = True 

204 self.member_registration.iban = "NL12ABNA1234567890" 

205 self.member_registration.signature = "base64,png" 

206 self.member_registration.initials = "J." 

207 self.member_registration.save() 

208 mail.outbox = [] 

209 

210 with self.subTest("With Thalia Pay"): 

211 # Completes the registration, does not send payment email, 

212 # but sends final email after completing the registration. 

213 services.accept_registration(self.member_registration, actor=self.admin) 

214 

215 self.member_registration.refresh_from_db() 

216 self.assertEqual(self.member_registration.status, Entry.STATUS_COMPLETED) 

217 self.assertIsNotNone(self.member_registration.membership) 

218 self.assertIsNotNone(self.member_registration.membership.user) 

219 member = self.member_registration.membership.user 

220 self.assertEqual(BankAccount.objects.filter(owner_id=member.id).count(), 1) 

221 self.assertEqual(self.member_registration.payment.amount, 7.5) 

222 self.assertEqual(self.member_registration.payment.type, Payment.TPAY) 

223 self.assertEqual(len(mail.outbox), 1) 

224 self.assertEqual( 

225 mail.outbox[0].subject, 

226 "[THALIA] Welcome to Study Association Thalia", 

227 ) 

228 

229 def test_reject_registration(self): 

230 with self.subTest("Not in review."): 

231 with self.assertRaises(ValueError): 

232 services.reject_registration(self.member_registration, actor=self.admin) 

233 

234 self.member_registration.status = Entry.STATUS_REVIEW 

235 self.member_registration.save() 

236 

237 services.reject_registration(self.member_registration, actor=self.admin) 

238 self.assertEqual(self.member_registration.status, Entry.STATUS_REJECTED) 

239 self.assertEqual(len(mail.outbox), 1) 

240 

241 def test_revert_registration(self): 

242 with self.subTest("Not accepted or rejected."): 

243 with self.assertRaises(ValueError): 

244 services.revert_registration(self.member_registration, actor=self.admin) 

245 

246 self.member_registration.status = Entry.STATUS_REJECTED 

247 self.member_registration.save() 

248 

249 with self.subTest("Revert rejected registration."): 

250 services.revert_registration(self.member_registration, actor=self.admin) 

251 self.assertEqual(self.member_registration.status, Entry.STATUS_REVIEW) 

252 

253 self.member_registration.status = Entry.STATUS_ACCEPTED 

254 self.member_registration.save() 

255 

256 with override_settings(SUSPEND_SIGNALS=True): 

257 payment = create_payment(self.member_registration, self.admin, Payment.CASH) 

258 # Signals are suspended, so this does not complete the registration. 

259 self.member_registration.refresh_from_db() 

260 self.assertEqual(self.member_registration.status, Entry.STATUS_ACCEPTED) 

261 

262 with self.subTest("Revert paid, but somehow not completed registration."): 

263 # As of now, it should no longer be possible to create a payment without 

264 # completing the registration successfully, but still, revert_registration 

265 # should be able to handle this. 

266 services.revert_registration(self.member_registration, actor=self.admin) 

267 self.assertEqual(self.member_registration.status, Entry.STATUS_REVIEW) 

268 self.assertFalse(Payment.objects.filter(pk=payment.pk).exists()) 

269 

270 def test_complete_registration(self): 

271 with self.subTest("Not accepted."): 

272 with self.assertRaises(ValueError): 

273 services.complete_registration(self.member_registration) 

274 

275 self.member_registration.status = Entry.STATUS_ACCEPTED 

276 self.member_registration.save() 

277 

278 with self.subTest("No payment."): 

279 with self.assertRaises(ValueError): 

280 services.complete_registration(self.member_registration) 

281 

282 with self.subTest("Complete member registration when payment is made."): 

283 # Signal triggers call to complete_registration. 

284 with freeze_time("2023-08-28"): 

285 create_payment(self.member_registration, self.admin, Payment.CASH) 

286 

287 self.member_registration.refresh_from_db() 

288 self.assertEqual(self.member_registration.status, Entry.STATUS_COMPLETED) 

289 membership = self.member_registration.membership 

290 self.assertIsNotNone(membership) 

291 member = membership.user 

292 self.assertEqual(member.first_name, "John") 

293 self.assertEqual(member.last_name, "Doe") 

294 self.assertEqual(member.username, "jdoe") 

295 

296 # Membership starts on the day the registration is completed, 

297 # even though this is before the start of the year (2023-09-01). 

298 # This makes it possible for first-year students to become a member during 

299 # the introduction week without having to wait for another week to actually 

300 # be a member and use the website. 

301 self.assertEqual(membership.since, date(2023, 8, 28)) 

302 

303 self.assertEqual(membership.until, date(2024, 9, 1)) 

304 self.assertEqual(membership.type, Membership.MEMBER) 

305 self.assertFalse(member.bank_accounts.all().exists()) 

306 

307 self.assertEqual(len(mail.outbox), 1) 

308 

309 with self.subTest("Complete Honorary membership registration"): 

310 self.honory_registration.status = Entry.STATUS_ACCEPTED 

311 self.honory_registration.save() 

312 create_payment(self.honory_registration, self.admin, Payment.CASH) 

313 self.honory_registration.refresh_from_db() 

314 self.assertEqual(self.honory_registration.status, Entry.STATUS_COMPLETED) 

315 membership = self.honory_registration.membership 

316 self.assertIsNotNone(membership) 

317 self.assertEqual(membership.type, Membership.HONORARY) 

318 self.assertIsNone(membership.until) 

319 

320 self.benefactor_registration.status = Entry.STATUS_ACCEPTED 

321 self.benefactor_registration.username = None # Default 'jdoe' is taken already. 

322 self.benefactor_registration.save() 

323 mail.outbox = [] 

324 

325 with self.subTest("Username is not unique."): 

326 # Signal triggers call to complete_registration, which raises. 

327 # Creating the payment is rolled back. The registration remains accepted. 

328 with self.assertRaises(PaymentError): 

329 create_payment(self.benefactor_registration, self.admin, Payment.CASH) 

330 

331 self.benefactor_registration.refresh_from_db() 

332 self.assertEqual(self.benefactor_registration.status, Entry.STATUS_ACCEPTED) 

333 self.assertIsNone(self.benefactor_registration.payment) 

334 self.assertEqual(len(mail.outbox), 0) 

335 

336 self.benefactor_registration.status = Entry.STATUS_ACCEPTED 

337 self.benefactor_registration.username = "janedoe" 

338 self.benefactor_registration.save() 

339 mail.outbox = [] 

340 

341 with self.subTest("Complete benefactor registration when payment is made."): 

342 # Signal triggers call to complete_registration. 

343 create_payment(self.benefactor_registration, self.admin, Payment.CASH) 

344 

345 self.benefactor_registration.refresh_from_db() 

346 self.assertEqual( 

347 self.benefactor_registration.status, Entry.STATUS_COMPLETED 

348 ) 

349 membership = self.benefactor_registration.membership 

350 self.assertIsNotNone(membership) 

351 member = membership.user 

352 self.assertEqual(member.first_name, "Jane") 

353 self.assertEqual(member.last_name, "Doe") 

354 self.assertEqual(member.username, "janedoe") 

355 self.assertEqual(membership.type, Membership.BENEFACTOR) 

356 self.assertEqual(len(mail.outbox), 1) 

357 self.assertEqual( 

358 mail.outbox[0].subject, 

359 "[THALIA] Welcome to Study Association Thalia", 

360 ) 

361 

362 self.study_time_member_registration.status = Entry.STATUS_ACCEPTED 

363 self.study_time_member_registration.save() 

364 mail.outbox = [] 

365 

366 with self.subTest("Complete study time registration when payment is made."): 

367 create_payment( 

368 self.study_time_member_registration, self.admin, Payment.CASH 

369 ) 

370 

371 self.study_time_member_registration.refresh_from_db() 

372 self.assertEqual( 

373 self.study_time_member_registration.status, Entry.STATUS_COMPLETED 

374 ) 

375 membership = self.study_time_member_registration.membership 

376 self.assertIsNotNone(membership) 

377 member = membership.user 

378 self.assertEqual(member.first_name, "Foo") 

379 self.assertEqual(member.last_name, "Bar") 

380 self.assertEqual(member.username, "fbar") 

381 self.assertEqual(membership.type, Membership.MEMBER) 

382 self.assertIsNotNone(membership.until) 

383 self.assertEqual(len(mail.outbox), 1) 

384 self.assertEqual( 

385 mail.outbox[0].subject, 

386 "[THALIA] Welcome to Study Association Thalia", 

387 ) 

388 

389 def test_complete_registration_after_start_of_year(self): 

390 self.member_registration.status = Entry.STATUS_ACCEPTED 

391 self.member_registration.save() 

392 

393 # Signal triggers call to complete_registration. 

394 with freeze_time("2023-09-10"): 

395 create_payment(self.member_registration, self.admin, Payment.CASH) 

396 

397 self.member_registration.refresh_from_db() 

398 self.assertEqual(self.member_registration.status, Entry.STATUS_COMPLETED) 

399 membership = self.member_registration.membership 

400 self.assertIsNotNone(membership) 

401 

402 # Membership starts on the day the registration is completed. 

403 self.assertEqual(membership.since, date(2023, 9, 10)) 

404 self.assertEqual(membership.until, date(2024, 9, 1)) 

405 

406 def test_accept_renewal(self): 

407 services.accept_renewal(self.renewal, actor=self.admin) 

408 

409 self.renewal.refresh_from_db() 

410 self.assertEqual(self.renewal.status, Entry.STATUS_ACCEPTED) 

411 self.assertEqual(len(mail.outbox), 1) 

412 self.assertEqual( 

413 mail.outbox[0].subject, 

414 "[THALIA] Renewal accepted", 

415 ) 

416 

417 mail.outbox = [] 

418 

419 with self.subTest("Not in review."): 

420 with self.assertRaises(ValueError): 

421 services.accept_renewal(self.renewal, actor=self.admin) 

422 

423 self.assertEqual(self.renewal.status, Entry.STATUS_ACCEPTED) 

424 self.assertEqual(len(mail.outbox), 0) 

425 

426 def test_reject_renewal(self): 

427 services.reject_renewal(self.renewal, actor=self.admin) 

428 

429 self.renewal.refresh_from_db() 

430 self.assertEqual(self.renewal.status, Entry.STATUS_REJECTED) 

431 self.assertEqual(len(mail.outbox), 1) 

432 self.assertEqual( 

433 mail.outbox[0].subject, 

434 "[THALIA] Renewal rejected", 

435 ) 

436 

437 mail.outbox = [] 

438 

439 with self.subTest("Not in review."): 

440 with self.assertRaises(ValueError): 

441 services.reject_renewal(self.renewal, actor=self.admin) 

442 

443 self.assertEqual(self.renewal.status, Entry.STATUS_REJECTED) 

444 self.assertEqual(len(mail.outbox), 0) 

445 

446 def test_revert_renewal(self): 

447 with self.subTest("Not accepted or rejected."): 

448 with self.assertRaises(ValueError): 

449 services.revert_renewal(self.member_registration, actor=self.admin) 

450 

451 self.renewal.status = Entry.STATUS_REJECTED 

452 self.renewal.save() 

453 

454 with self.subTest("Revert rejected renewal."): 

455 services.revert_renewal(self.renewal, actor=self.admin) 

456 self.assertEqual(self.renewal.status, Entry.STATUS_REVIEW) 

457 

458 self.renewal.status = Entry.STATUS_ACCEPTED 

459 self.renewal.save() 

460 

461 with override_settings(SUSPEND_SIGNALS=True): 

462 payment = create_payment(self.renewal, self.admin, Payment.CASH) 

463 # Signals are suspended, so this does not complete the renewal. 

464 self.renewal.refresh_from_db() 

465 self.assertEqual(self.renewal.status, Entry.STATUS_ACCEPTED) 

466 

467 with self.subTest("Revert paid, but somehow not completed renewal."): 

468 # As of now, it should no longer be possible to create a payment without 

469 # completing the renewal successfully, but still, revert_renewal 

470 # should be able to handle this. 

471 services.revert_renewal(self.renewal, actor=self.admin) 

472 self.assertEqual(self.renewal.status, Entry.STATUS_REVIEW) 

473 self.assertFalse(Payment.objects.filter(pk=payment.pk).exists()) 

474 

475 def test_complete_renewal(self): 

476 with self.subTest("Not accepted."): 

477 with self.assertRaises(ValueError): 

478 services.complete_renewal(self.renewal) 

479 

480 self.renewal.status = Entry.STATUS_ACCEPTED 

481 self.renewal.save() 

482 

483 with self.subTest("No payment."): 

484 with self.assertRaises(ValueError): 

485 services.complete_renewal(self.renewal) 

486 

487 with self.subTest("Complete renewal before end of latest membership."): 

488 with freeze_time("2023-08-27"): 

489 create_payment(self.renewal, self.admin, Payment.CASH) 

490 

491 self.renewal.refresh_from_db() 

492 self.assertEqual(self.renewal.status, Entry.STATUS_COMPLETED) 

493 membership = self.renewal.membership 

494 self.assertIsNotNone(membership) 

495 self.assertEqual(self.member.membership_set.all().count(), 2) 

496 

497 self.assertEqual(membership.since, date(2023, 9, 1)) 

498 self.assertEqual(membership.until, date(2024, 9, 1)) 

499 

500 # Restore data. 

501 with freeze_time("2023-08-25"): 

502 membership.delete() 

503 self.renewal.delete() 

504 self.renewal = Renewal.objects.create( 

505 member=self.member, 

506 length=Entry.MEMBERSHIP_YEAR, 

507 membership_type=Membership.MEMBER, 

508 contribution=7.5, 

509 ) 

510 

511 self.renewal.status = Entry.STATUS_ACCEPTED 

512 self.renewal.save() 

513 

514 with self.subTest("Complete renewal after end of latest membership."): 

515 with freeze_time("2023-09-10"): 

516 create_payment(self.renewal, self.admin, Payment.CASH) 

517 

518 self.renewal.refresh_from_db() 

519 self.assertEqual(self.renewal.status, Entry.STATUS_COMPLETED) 

520 membership = self.renewal.membership 

521 self.assertIsNotNone(membership) 

522 

523 self.assertEqual(membership.since, date(2023, 9, 10)) 

524 self.assertEqual(membership.until, date(2024, 9, 1)) 

525 

526 # Restore data. 

527 with freeze_time("2023-08-25"): 

528 membership.delete() 

529 self.renewal.delete() 

530 self.renewal = Renewal.objects.create( 

531 member=self.member, 

532 length=Entry.MEMBERSHIP_STUDY, 

533 membership_type=Membership.MEMBER, 

534 contribution=22.5, 

535 ) 

536 

537 self.renewal.status = Entry.STATUS_ACCEPTED 

538 self.renewal.save() 

539 

540 with freeze_time("2023-08-27"): 

541 with self.subTest( 

542 "Discounted membership upgrade before membership expiry." 

543 ): 

544 create_payment(self.renewal, self.admin, Payment.CASH) 

545 

546 self.renewal.refresh_from_db() 

547 self.assertEqual(self.renewal.status, Entry.STATUS_COMPLETED) 

548 membership = self.renewal.membership 

549 self.assertIsNotNone(membership) 

550 self.assertEqual(self.membership.pk, membership.pk) 

551 

552 # Restore data. 

553 with freeze_time("2023-08-25"): 

554 self.membership.until = "2023-09-01" 

555 self.membership.save() 

556 self.renewal.delete() 

557 self.renewal = Renewal.objects.create( 

558 member=self.member, 

559 length=Entry.MEMBERSHIP_STUDY, 

560 membership_type=Membership.MEMBER, 

561 contribution=22.5, 

562 ) 

563 

564 self.renewal.status = Entry.STATUS_ACCEPTED 

565 self.renewal.save() 

566 

567 with freeze_time("2023-09-10"): 

568 with self.subTest("Discounted membership upgrade after membership expiry."): 

569 create_payment(self.renewal, self.admin, Payment.CASH) 

570 

571 self.renewal.refresh_from_db() 

572 self.assertEqual(self.renewal.status, Entry.STATUS_COMPLETED) 

573 membership = self.renewal.membership 

574 self.assertIsNotNone(membership) 

575 self.assertEqual(self.membership.pk, membership.pk) 

576 

577 # Restore data. 

578 with freeze_time("2023-08-25"): 

579 self.membership.study_long = True 

580 self.membership.save() 

581 self.renewal.delete() 

582 self.renewal = Renewal.objects.create( 

583 member=self.member, 

584 length=Entry.MEMBERSHIP_STUDY, 

585 membership_type=Membership.MEMBER, 

586 contribution=22.5, 

587 ) 

588 

589 self.renewal.status = Entry.STATUS_ACCEPTED 

590 self.renewal.save() 

591 

592 with freeze_time("2023-09-10"): 

593 with self.subTest("Already has study-time membership."): 

594 with self.assertRaises(PaymentError): 

595 create_payment(self.renewal, self.admin, Payment.CASH) 

596 

597 self.renewal.length = Entry.MEMBERSHIP_YEAR 

598 self.renewal.save() 

599 

600 with self.subTest("Already has study-time membership."): 

601 with self.assertRaises(PaymentError): 

602 create_payment(self.renewal, self.admin, Payment.CASH) 

603 

604 # Restore data. 

605 with freeze_time("2023-09-05"): 

606 self.membership.until = "2023-09-01" 

607 self.membership.study_long = False 

608 self.membership.save() 

609 self.renewal.delete() 

610 self.renewal = Renewal.objects.create( 

611 member=self.member, 

612 length=Entry.MEMBERSHIP_STUDY, 

613 membership_type=Membership.MEMBER, 

614 contribution=30, 

615 ) 

616 

617 self.renewal.status = Entry.STATUS_ACCEPTED 

618 self.renewal.save() 

619 

620 with freeze_time("2023-09-10"): 

621 with self.subTest("Non-discounted membership upgrade."): 

622 create_payment(self.renewal, self.admin, Payment.CASH) 

623 

624 self.renewal.refresh_from_db() 

625 self.assertEqual(self.renewal.status, Entry.STATUS_COMPLETED) 

626 membership = self.renewal.membership 

627 self.assertIsNotNone(membership) 

628 self.assertEqual(self.membership.pk, membership.pk) 

629 

630 # Restore data. 

631 with freeze_time("2023-09-05"): 

632 membership.delete() 

633 self.membership.until = "2023-09-01" 

634 self.membership.type = Membership.BENEFACTOR 

635 self.membership.save() 

636 self.renewal.delete() 

637 self.renewal = Renewal.objects.create( 

638 member=self.member, 

639 length=Entry.MEMBERSHIP_YEAR, 

640 membership_type=Membership.BENEFACTOR, 

641 contribution=30, 

642 ) 

643 

644 self.renewal.status = Entry.STATUS_ACCEPTED 

645 self.renewal.save() 

646 

647 with freeze_time("2023-09-10"): 

648 with self.subTest("Complete benefactor renewal."): 

649 create_payment(self.renewal, self.admin, Payment.CASH) 

650 

651 self.renewal.refresh_from_db() 

652 self.assertEqual(self.renewal.status, Entry.STATUS_COMPLETED) 

653 membership = self.renewal.membership 

654 self.assertIsNotNone(membership) 

655 self.assertNotEqual(self.membership.pk, membership.pk) 

656 

657 self.assertEqual(membership.since, date(2023, 9, 10)) 

658 self.assertEqual(membership.until, date(2024, 9, 1)) 

659 self.assertEqual(membership.type, Membership.BENEFACTOR) 

660 

661 def test_data_minimisation(self): 

662 with freeze_time("2025-01-01"): 

663 with self.subTest("No old completed registrations."): 

664 self.assertEqual(services.execute_data_minimisation(), 0) 

665 

666 with freeze_time("2024-09-10"): 

667 self.renewal.status = Entry.STATUS_COMPLETED 

668 self.renewal.updated_at = timezone.now() 

669 self.renewal.save() 

670 self.member_registration.status = Entry.STATUS_COMPLETED 

671 self.member_registration.updated_at = timezone.now() 

672 self.member_registration.save() 

673 

674 self.assertEqual(Registration.objects.count(), 4) 

675 self.assertEqual(Renewal.objects.count(), 1) 

676 

677 with freeze_time("2024-09-15"): 

678 with self.subTest("A recent completed registration and renewal."): 

679 services.execute_data_minimisation() 

680 self.assertEqual(Registration.objects.count(), 4) 

681 self.assertEqual(Renewal.objects.count(), 1) 

682 

683 with freeze_time("2024-10-15"): 

684 with self.subTest("Dry run."): 

685 services.execute_data_minimisation(dry_run=True) 

686 self.assertEqual(Registration.objects.count(), 4) 

687 self.assertEqual(Renewal.objects.count(), 1) 

688 

689 with self.subTest("An old completed registration and renewal."): 

690 services.execute_data_minimisation() 

691 self.assertEqual(Registration.objects.count(), 3) 

692 self.assertEqual(Renewal.objects.count(), 0)