3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
10 * Copyright © 2017-2023 The Galette Team
12 * This file is part of Galette (http://galette.tuxfamily.org).
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
28 * @package GaletteTests
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2017-2023 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
37 namespace Galette\Entity\test\units
;
39 use Galette\GaletteTestCase
;
42 * Contribution tests class
46 * @package GaletteTests
47 * @author Johan Cwiklinski <johan@x-tnd.be>
48 * @copyright 2017-2023 The Galette Team
49 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
50 * @link http://galette.tuxfamily.org
53 class Contribution
extends GaletteTestCase
55 protected int $seed = 95842354;
58 * Cleanup after each test method
62 public function tearDown(): void
66 $this->zdb
= new \Galette\Core\
Db();
67 $delete = $this->zdb
->delete(\Galette\Entity\Contribution
::TABLE
);
68 $delete->where(['info_cotis' => 'FAKER' . $this->seed
]);
69 $this->zdb
->execute($delete);
71 $delete = $this->zdb
->delete(\Galette\Entity\Adherent
::TABLE
);
72 $delete->where(['fingerprint' => 'FAKER' . $this->seed
]);
73 $delete->where('parent_id IS NOT NULL');
74 $this->zdb
->execute($delete);
76 $delete = $this->zdb
->delete(\Galette\Entity\Adherent
::TABLE
);
77 $delete->where(['fingerprint' => 'FAKER' . $this->seed
]);
78 $this->zdb
->execute($delete);
86 public function setUp(): void
89 $this->initContributionsTypes();
91 $this->contrib
= new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
93 $this->adh
= new \Galette\Entity\
Adherent($this->zdb
);
94 $this->adh
->setDependencies(
96 $this->members_fields
,
102 * Test empty contribution
106 public function testEmpty()
108 $contrib = $this->contrib
;
109 $this->assertNull($contrib->id
);
110 $this->assertNull($contrib->isFee());
111 $this->assertNull($contrib->is_cotis
);
112 $this->assertNull($contrib->date
);
113 $this->assertNull($contrib->begin_date
);
114 $this->assertNull($contrib->end_date
);
115 $this->assertNull($contrib->raw_date
);
116 $this->assertNull($contrib->raw_begin_date
);
117 $this->assertNull($contrib->raw_end_date
);
118 $this->assertEmpty($contrib->duration
);
119 $this->assertSame((int)$this->preferences
->pref_default_paymenttype
, $contrib->payment_type
);
120 $this->assertSame('Check', $contrib->spayment_type
);
121 $this->assertNull($contrib->model
);
122 $this->assertNull($contrib->member
);
123 $this->assertNull($contrib->type
);
124 $this->assertNull($contrib->amount
);
125 $this->assertNull($contrib->orig_amount
);
126 $this->assertNull($contrib->info
);
127 $this->assertNull($contrib->transaction
);
128 $this->assertCount(11, $contrib->fields
);
129 $this->assertTrue(isset($contrib->fields
[\Galette\Entity\Contribution
::PK
]));
130 $this->assertTrue(isset($contrib->fields
[\Galette\Entity\Adherent
::PK
]));
131 $this->assertTrue(isset($contrib->fields
[\Galette\Entity\ContributionsTypes
::PK
]));
132 $this->assertTrue(isset($contrib->fields
['montant_cotis']));
133 $this->assertTrue(isset($contrib->fields
['type_paiement_cotis']));
134 $this->assertTrue(isset($contrib->fields
['info_cotis']));
135 $this->assertTrue(isset($contrib->fields
['date_debut_cotis']));
137 $this->assertSame('cotis-give', $contrib->getRowClass());
138 $this->assertNull($contrib::getDueDate($this->zdb
, 1));
139 $this->assertFalse($contrib->isTransactionPart());
140 $this->assertFalse($contrib->isTransactionPartOf(1));
141 $this->assertSame('donation', $contrib->getRawType());
142 $this->assertSame('Donation', $contrib->getTypeLabel());
143 $this->assertSame('Check', $contrib->getPaymentType());
144 $this->assertNull($contrib->unknown_property
);
148 * Test getter and setter special cases
152 public function testGetterSetter()
154 $contrib = $this->contrib
;
157 $contrib->begin_date
= 'not a date';
158 $this->assertNull($contrib->raw_begin_date
);
159 $this->assertNull($contrib->begin_date
);
161 $contrib->begin_date
= '2017-06-17';
162 $this->assertInstanceOf('DateTime', $contrib->raw_begin_date
);
163 $this->assertSame('2017-06-17', $contrib->begin_date
);
165 $contrib->amount
= 'not an amount';
166 $this->assertNull($contrib->amount
);
167 $contrib->amount
= 0;
168 $this->assertNull($contrib->amount
);
169 $contrib->amount
= 42;
170 $this->assertSame(42, $contrib->amount
);
171 $contrib->amount
= '42';
172 $this->assertSame('42', $contrib->amount
);
174 $contrib->type
= 'not a type';
175 $this->assertNull($contrib->type
);
176 $contrib->type
= 156;
177 $this->assertInstanceOf('\Galette\Entity\ContributionsTypes', $contrib->type
);
178 $this->assertFalse($contrib->type
->id
);
180 $this->assertInstanceOf('\Galette\Entity\ContributionsTypes', $contrib->type
);
181 $this->assertEquals(1, $contrib->type
->id
);
183 $contrib->transaction
= 'not a transaction id';
184 $this->assertNull($contrib->transaction
);
185 $contrib->transaction
= 46;
186 $this->assertInstanceOf('\Galette\Entity\Transaction', $contrib->transaction
);
187 $this->assertNull($contrib->transaction
->id
);
189 $contrib->member
= 'not a member';
190 $this->assertNull($contrib->member
);
191 $contrib->member
= 118218;
192 $this->assertSame(118218, $contrib->member
);
194 $contrib->not_a_property
= 'abcde';
195 $this->assertFalse(property_exists($contrib, 'not_a_property'));
197 $contrib->payment_type
= \Galette\Entity\PaymentType
::CASH
;
198 $this->assertSame('Cash', $contrib->getPaymentType());
199 $this->assertSame('Cash', $contrib->spayment_type
);
201 $contrib->payment_type
= \Galette\Entity\PaymentType
::CHECK
;
202 $this->assertSame('Check', $contrib->getPaymentType());
203 $this->assertSame('Check', $contrib->spayment_type
);
205 $contrib->payment_type
= \Galette\Entity\PaymentType
::OTHER
;
206 $this->assertSame('Other', $contrib->getPaymentType());
207 $this->assertSame('Other', $contrib->spayment_type
);
209 $contrib->payment_type
= \Galette\Entity\PaymentType
::CREDITCARD
;
210 $this->assertSame('Credit card', $contrib->getPaymentType());
211 $this->assertSame('Credit card', $contrib->spayment_type
);
213 $contrib->payment_type
= \Galette\Entity\PaymentType
::TRANSFER
;
214 $this->assertSame('Transfer', $contrib->getPaymentType());
215 $this->assertSame('Transfer', $contrib->spayment_type
);
217 $contrib->payment_type
= \Galette\Entity\PaymentType
::PAYPAL
;
218 $this->assertSame('Paypal', $contrib->getPaymentType());
219 $this->assertSame('Paypal', $contrib->spayment_type
);
223 * Test contribution creation
227 public function testCreation()
229 $this->getMemberOne();
230 //create contribution for member
231 $this->createContribution();
235 * Test contribution update
239 public function testUpdate()
241 $this->getMemberOne();
242 //create contribution for member
243 $begin_date = new \
DateTime(); // 2020-11-07
244 $begin_date->sub(new \
DateInterval('P5M')); // 2020-06-07
245 $begin_date->add(new \
DateInterval('P3D')); // 2020-06-10
247 $due_date = clone $begin_date;
248 $due_date->add(new \
DateInterval('P1Y'));
249 $due_date->sub(new \
DateInterval('P1D'));
252 'id_adh' => $this->adh
->id
,
253 'id_type_cotis' => 4, //donation
254 'montant_cotis' => 12,
255 'type_paiement_cotis' => 3,
256 'info_cotis' => 'FAKER' . $this->seed
,
257 'date_enreg' => $begin_date->format('Y-m-d'),
258 'date_debut_cotis' => $begin_date->format('Y-m-d'),
259 'date_fin_cotis' => $due_date->format('Y-m-d'),
261 $this->createContrib($data);
264 'id_type_cotis' => 1,
267 'date_debut_cotis' => 1,
268 'date_fin_cotis' => 0,
271 $this->contrib
->getRequired()
274 $this->logSuperAdmin();
276 'id_adh' => $this->adh
->id
,
277 'id_type_cotis' => 4, //donation
278 'montant_cotis' => 1280,
279 'type_paiement_cotis' => 4,
280 'info_cotis' => 'FAKER' . $this->seed
,
281 'date_enreg' => $begin_date->format('Y-m-d'),
282 'date_debut_cotis' => $begin_date->format('Y-m-d'),
283 'date_fin_cotis' => $due_date->format('Y-m-d'),
285 $this->createContrib($data);
287 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
, $this->contrib
->id
);
288 $this->assertSame(1280.00, $contrib->amount
);
292 'id_adh' => $this->adh
->id
,
293 'id_type_cotis' => 4, //donation
294 'montant_cotis' => '',
295 'type_paiement_cotis' => 4,
296 'info_cotis' => 'FAKER' . $this->seed
,
297 'date_enreg' => $begin_date->format('Y-m-d'),
298 'date_debut_cotis' => $begin_date->format('Y-m-d'),
299 'date_fin_cotis' => $due_date->format('Y-m-d'),
301 $this->createContrib($data);
303 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
, $this->contrib
->id
);
304 $this->assertSame(0.00, $contrib->amount
);
308 * Test end date retrieving
309 * This is based on some Preferences parameters
313 public function testRetrieveEndDate()
316 $orig_pref_beg_membership = $this->preferences
->pref_beg_membership
;
317 $orig_pref_membership_ext = $this->preferences
->pref_membership_ext
;
318 $orig_pref_membership_offermonths = $this->preferences
->pref_membership_offermonths
;
320 $contrib = new \Galette\Entity\
Contribution(
323 ['type' => 1] //annual fee
326 // First, check for 12 months renewal
327 $due_date = new \
DateTime();
328 $due_date->add(new \
DateInterval('P1Y'));
329 $due_date->sub(new \
DateInterval('P1D'));
330 $this->assertSame($due_date->format('Y-m-d'), $contrib->end_date
);
332 //unset pref_beg_membership and pref_membership_ext
333 $preferences->pref_beg_membership
= '';
334 $preferences->pref_membership_ext
= '';
336 $this->expectException('RuntimeException');
337 $this->expectExceptionMessage('Unable to define end date; none of pref_beg_membership nor pref_membership_ext are defined!');
338 $contrib = new \Galette\Entity\
Contribution(
341 ['type' => 1] //annual fee
344 // Second, test with beginning of membership date
345 $preferences->pref_beg_membership
= '29/05';
346 $due_date = new \
DateTime();
347 $due_date->setDate(date('Y'), 5, 28);
348 if ($due_date <= new \
DateTime()) {
349 $due_date->add(new \
DateInterval('P1Y'));
352 $contrib = new \Galette\Entity\
Contribution(
355 ['type' => 1] // annual fee
357 $this->assertSame($due_date->format('Y-m-d'), $contrib->end_date
);
359 // Third, test with beginning of membership date and 2 last months offered
360 $begin_date = new \
DateTime();
361 $begin_date->add(new \
DateInterval('P1M'));
362 $preferences->pref_beg_membership
= $begin_date->format('01/m');
363 $preferences->pref_membership_offermonths
= 2;
364 $due_date = new \
DateTime($begin_date->format('Y-m-01'));
365 $due_date->add(new \
DateInterval('P1Y'));
366 $due_date->sub(new \
DateInterval('P1D'));
368 $contrib = new \Galette\Entity\
Contribution(
371 ['type' => 1] // annual fee
373 $this->assertSame($due_date->format('Y-m-d'), $contrib->end_date
);
376 $preferences->pref_beg_membership
= $orig_pref_beg_membership;
377 $preferences->pref_membership_ext
= $orig_pref_membership_ext;
378 $preferences->pref_membership_offermonths
= $orig_pref_membership_offermonths;
382 * Test checkOverlap method
386 public function testCheckOverlap()
388 $adh = new \Galette\Entity\
Adherent($this->zdb
);
389 $adh->setDependencies(
391 $this->members_fields
,
395 $check = $adh->check(
397 'nom_adh' => 'Overlapped',
398 'date_crea_adh' => date(_T("Y-m-d")),
399 \Galette\Entity\Status
::PK
=> \Galette\Entity\Status
::DEFAULT_STATUS
,
400 'fingerprint' => 'FAKER' . $this->seed
405 if (is_array($check)) {
408 $this->assertTrue($check);
410 $store = $adh->store();
411 $this->assertTrue($store);
413 //create first contribution for member
414 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
416 $now = new \
DateTime();
417 $due_date = clone $now;
418 $due_date->add(new \
DateInterval('P1Y'));
419 $due_date->sub(new \
DateInterval('P1D'));
421 \Galette\Entity\Adherent
::PK
=> $adh->id
,
422 \Galette\Entity\ContributionsTypes
::PK
=> 1, //annual fee
423 'montant_cotis' => 20,
424 'type_paiement_cotis' => \Galette\Entity\PaymentType
::CHECK
,
425 'date_enreg' => $now->format(_T("Y-m-d")),
426 'date_debut_cotis' => $now->format(_T("Y-m-d")),
427 'date_fin_cotis' => $due_date->format(_T("Y-m-d")),
428 'info_cotis' => 'FAKER' . $this->seed
431 $check = $contrib->check($data, [], []);
432 if (is_array($check)) {
435 $this->assertTrue($check);
436 $this->assertTrue($contrib->checkOverlap());
438 $store = $contrib->store();
439 $this->assertTrue($store);
441 //load member from db
442 $adh = new \Galette\Entity\
Adherent($this->zdb
, $adh->id
);
444 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
445 $begin_date = clone $due_date;
446 $begin_date->add(new \
DateInterval('P1D'));
447 $begin_date->sub(new \
DateInterval('P3M'));
448 $due_date = clone $begin_date;
449 $due_date->add(new \
DateInterval('P1Y'));
450 $due_date->sub(new \
DateInterval('P1D'));
452 \Galette\Entity\Adherent
::PK
=> $adh->id
,
453 \Galette\Entity\ContributionsTypes
::PK
=> 1, //annual fee
454 'montant_cotis' => 20,
455 'type_paiement_cotis' => \Galette\Entity\PaymentType
::CHECK
,
456 'date_enreg' => $now->format(_T("Y-m-d")),
457 'date_debut_cotis' => $begin_date->format(_T("Y-m-d")),
458 'date_fin_cotis' => $due_date->format(_T("Y-m-d")),
459 'info_cotis' => 'FAKER' . $this->seed
462 $check = $contrib->check($data, [], []);
465 '- Membership period overlaps period starting at ' . $now->format('Y-m-d')
470 $this->expectException('RuntimeException');
471 $this->expectExceptionMessage('Existing errors prevents storing contribution');
472 $store = $contrib->store();
480 public function testGetFieldLabel()
484 $this->contrib
->getFieldLabel('montant_cotis')
488 'Date of contribution',
489 $this->contrib
->getFieldLabel('date_debut_cotis')
492 $this->contrib
->type
= 1;
494 'Start date of membership',
495 $this->contrib
->getFieldLabel('date_debut_cotis')
500 $this->contrib
->getFieldLabel('info_cotis')
505 * Test contribution loading
509 public function testLoad()
511 $this->login
= $this->getMockBuilder(\Galette\Core\Login
::class)
512 ->setConstructorArgs(array($this->zdb
, $this->i18n
))
513 ->onlyMethods(array('isLogged', 'isStaff', 'isAdmin'))
515 $this->login
->method('isLogged')->willReturn(true);
516 $this->login
->method('isStaff')->willReturn(true);
517 $this->login
->method('isAdmin')->willReturn(true);
519 $this->getMemberOne();
521 //create contribution for member
522 $this->createContribution();
524 $id = $this->contrib
->id
;
525 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
527 $this->assertTrue($contrib->load((int)$id));
528 $this->checkContribExpected($contrib);
530 $this->assertFalse($contrib->load(1355522012));
534 * Test contribution removal
538 public function testRemove()
540 $this->getMemberOne();
541 $this->createContribution();
543 $this->assertTrue($this->contrib
->remove());
544 $this->assertFalse($this->contrib
->remove());
552 public function testCan()
554 $this->getMemberOne();
555 //create contribution for member
556 $this->createContribution();
557 $contrib = $this->contrib
;
559 $this->assertFalse($contrib->canShow($this->login
));
561 //Superadmin can fully change contributions
562 $this->logSuperAdmin();
564 $this->assertTrue($contrib->canShow($this->login
));
567 $this->login
->logOut();
568 $this->assertFalse($this->login
->isLogged());
570 //Member can fully change its own contributions
571 $mdata = $this->dataAdherentOne();
572 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
573 $this->assertTrue($this->login
->isLogged());
574 $this->assertFalse($this->login
->isAdmin());
575 $this->assertFalse($this->login
->isStaff());
577 $this->assertTrue($contrib->canShow($this->login
));
580 $this->login
->logOut();
581 $this->assertFalse($this->login
->isLogged());
583 //Another member has no access
584 $this->getMemberTwo();
585 $mdata = $this->dataAdherentTwo();
586 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
587 $this->assertTrue($this->login
->isLogged());
588 $this->assertFalse($this->login
->isAdmin());
589 $this->assertFalse($this->login
->isStaff());
591 $this->assertFalse($contrib->canShow($this->login
));
593 //parents can chow change children contributions
594 $this->getMemberOne();
595 $member = $this->adh
;
596 $mdata = $this->dataAdherentOne();
598 $login = $this->login
;
599 $this->logSuperAdmin();
603 'prenom_adh' => 'Johny',
604 'parent_id' => $member->id
,
606 'login_adh' => 'child.johny.doe',
607 'fingerprint' => 'FAKER' . $this->seed
609 $child = $this->createMember($child_data);
612 //contribution for child
613 $begin_date = new \
DateTime(); // 2020-11-07
614 $begin_date->sub(new \
DateInterval('P5M')); // 2020-06-07
615 $begin_date->add(new \
DateInterval('P3D')); // 2020-06-10
617 $due_date = clone $begin_date;
618 $due_date->add(new \
DateInterval('P1Y'));
619 $due_date->sub(new \
DateInterval('P1D'));
623 'id_type_cotis' => 1,
624 'montant_cotis' => 25,
625 'type_paiement_cotis' => 3,
626 'info_cotis' => 'FAKER' . $this->seed
,
627 'date_enreg' => $begin_date->format('Y-m-d'),
628 'date_debut_cotis' => $begin_date->format('Y-m-d'),
629 'date_fin_cotis' => $due_date->format('Y-m-d'),
631 $ccontrib = $this->createContrib($data);
633 $this->login
->logOut();
636 $child = new \Galette\Entity\
Adherent($this->zdb
);
637 $child->enableDep('parent');
638 $this->assertTrue($child->load($cid));
640 $this->assertSame($child_data['nom_adh'], $child->name
);
641 $this->assertInstanceOf('\Galette\Entity\Adherent', $child->parent
);
642 $this->assertSame($member->id
, $child->parent
->id
);
643 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
645 $mdata = $this->dataAdherentOne();
646 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
647 $this->assertTrue($this->login
->isLogged());
648 $this->assertFalse($this->login
->isAdmin());
649 $this->assertFalse($this->login
->isStaff());
651 $this->assertTrue($ccontrib->canShow($this->login
));
654 $this->login
->logOut();
655 $this->assertFalse($this->login
->isLogged());