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 donation update
239 public function testDonationUpdate()
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 contribution update
312 public function testContributionUpdate()
314 $this->logSuperAdmin();
316 $this->getMemberOne();
317 //create contribution for member
318 $begin_date = new \
DateTime(); // 2020-11-07
319 $begin_date->sub(new \
DateInterval('P5M')); // 2020-06-07
320 $begin_date->add(new \
DateInterval('P3D')); // 2020-06-10
322 $due_date = clone $begin_date;
323 $due_date->add(new \
DateInterval('P1Y'));
324 $due_date->sub(new \
DateInterval('P1D'));
326 //instanciate contribution as annual fee
327 $this->contrib
= new \Galette\Entity\
Contribution(
331 'type' => 1 //annual fee
336 'id_type_cotis' => 1,
339 'date_debut_cotis' => 1,
340 'date_fin_cotis' => 1, //should be 1
341 'montant_cotis' => 1 // should be 1
343 $this->contrib
->getRequired()
347 'id_adh' => $this->adh
->id
,
348 'id_type_cotis' => 1, //annual fee
349 'montant_cotis' => 0,
350 'type_paiement_cotis' => 3,
351 'info_cotis' => 'FAKER' . $this->seed
,
352 'date_enreg' => $begin_date->format('Y-m-d'),
353 'date_debut_cotis' => $begin_date->format('Y-m-d'),
354 'date_fin_cotis' => $due_date->format('Y-m-d'),
357 $this->createContrib($data, $this->contrib
);
359 $this->assertSame(0.0, $this->contrib
->amount
);
360 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
, $this->contrib
->id
);
361 $this->assertSame(0.0, $contrib->amount
);
364 $data['montant_cotis'] = 42;
365 $check = $contrib->check($data, [], []);
366 if (is_array($check)) {
369 $this->assertTrue($check);
371 $store = $contrib->store();
372 $this->assertTrue($store);
374 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
, $this->contrib
->id
);
375 $this->assertSame(42.0, $contrib->amount
);
377 //change amount back to 0
378 $data['montant_cotis'] = 0;
379 $check = $contrib->check($data, [], []);
380 if (is_array($check)) {
383 $this->assertTrue($check);
385 $store = $contrib->store();
386 $this->assertTrue($store);
388 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
, $this->contrib
->id
);
389 $this->assertSame(0.0, $contrib->amount
);
393 * Test end date retrieving
394 * This is based on some Preferences parameters
398 public function testRetrieveEndDate()
401 $orig_pref_beg_membership = $this->preferences
->pref_beg_membership
;
402 $orig_pref_membership_ext = $this->preferences
->pref_membership_ext
;
403 $orig_pref_membership_offermonths = $this->preferences
->pref_membership_offermonths
;
405 $contrib = new \Galette\Entity\
Contribution(
408 ['type' => 1] //annual fee
411 // First, check for 12 months renewal
412 $due_date = new \
DateTime();
413 $due_date->add(new \
DateInterval('P1Y'));
414 $due_date->sub(new \
DateInterval('P1D'));
415 $this->assertSame($due_date->format('Y-m-d'), $contrib->end_date
);
417 //unset pref_beg_membership and pref_membership_ext
418 $preferences->pref_beg_membership
= '';
419 $preferences->pref_membership_ext
= '';
421 $this->expectException('RuntimeException');
422 $this->expectExceptionMessage('Unable to define end date; none of pref_beg_membership nor pref_membership_ext are defined!');
423 $contrib = new \Galette\Entity\
Contribution(
426 ['type' => 1] //annual fee
429 // Second, test with beginning of membership date
430 $preferences->pref_beg_membership
= '29/05';
431 $due_date = new \
DateTime();
432 $due_date->setDate(date('Y'), 5, 28);
433 if ($due_date <= new \
DateTime()) {
434 $due_date->add(new \
DateInterval('P1Y'));
437 $contrib = new \Galette\Entity\
Contribution(
440 ['type' => 1] // annual fee
442 $this->assertSame($due_date->format('Y-m-d'), $contrib->end_date
);
444 // Third, test with beginning of membership date and 2 last months offered
445 $begin_date = new \
DateTime();
446 $begin_date->add(new \
DateInterval('P1M'));
447 $preferences->pref_beg_membership
= $begin_date->format('01/m');
448 $preferences->pref_membership_offermonths
= 2;
449 $due_date = new \
DateTime($begin_date->format('Y-m-01'));
450 $due_date->add(new \
DateInterval('P1Y'));
451 $due_date->sub(new \
DateInterval('P1D'));
453 $contrib = new \Galette\Entity\
Contribution(
456 ['type' => 1] // annual fee
458 $this->assertSame($due_date->format('Y-m-d'), $contrib->end_date
);
461 $preferences->pref_beg_membership
= $orig_pref_beg_membership;
462 $preferences->pref_membership_ext
= $orig_pref_membership_ext;
463 $preferences->pref_membership_offermonths
= $orig_pref_membership_offermonths;
467 * Test checkOverlap method
471 public function testCheckOverlap()
473 $adh = new \Galette\Entity\
Adherent($this->zdb
);
474 $adh->setDependencies(
476 $this->members_fields
,
480 $check = $adh->check(
482 'nom_adh' => 'Overlapped',
483 'date_crea_adh' => date(_T("Y-m-d")),
484 \Galette\Entity\Status
::PK
=> \Galette\Entity\Status
::DEFAULT_STATUS
,
485 'fingerprint' => 'FAKER' . $this->seed
490 if (is_array($check)) {
493 $this->assertTrue($check);
495 $store = $adh->store();
496 $this->assertTrue($store);
498 //create first contribution for member
499 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
501 $now = new \
DateTime();
502 $due_date = clone $now;
503 $due_date->add(new \
DateInterval('P1Y'));
504 $due_date->sub(new \
DateInterval('P1D'));
506 \Galette\Entity\Adherent
::PK
=> $adh->id
,
507 \Galette\Entity\ContributionsTypes
::PK
=> 1, //annual fee
508 'montant_cotis' => 20,
509 'type_paiement_cotis' => \Galette\Entity\PaymentType
::CHECK
,
510 'date_enreg' => $now->format(_T("Y-m-d")),
511 'date_debut_cotis' => $now->format(_T("Y-m-d")),
512 'date_fin_cotis' => $due_date->format(_T("Y-m-d")),
513 'info_cotis' => 'FAKER' . $this->seed
516 $check = $contrib->check($data, [], []);
517 if (is_array($check)) {
520 $this->assertTrue($check);
521 $this->assertTrue($contrib->checkOverlap());
523 $store = $contrib->store();
524 $this->assertTrue($store);
526 //load member from db
527 $adh = new \Galette\Entity\
Adherent($this->zdb
, $adh->id
);
529 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
530 $begin_date = clone $due_date;
531 $begin_date->add(new \
DateInterval('P1D'));
532 $begin_date->sub(new \
DateInterval('P3M'));
533 $due_date = clone $begin_date;
534 $due_date->add(new \
DateInterval('P1Y'));
535 $due_date->sub(new \
DateInterval('P1D'));
537 \Galette\Entity\Adherent
::PK
=> $adh->id
,
538 \Galette\Entity\ContributionsTypes
::PK
=> 1, //annual fee
539 'montant_cotis' => 20,
540 'type_paiement_cotis' => \Galette\Entity\PaymentType
::CHECK
,
541 'date_enreg' => $now->format(_T("Y-m-d")),
542 'date_debut_cotis' => $begin_date->format(_T("Y-m-d")),
543 'date_fin_cotis' => $due_date->format(_T("Y-m-d")),
544 'info_cotis' => 'FAKER' . $this->seed
547 $check = $contrib->check($data, [], []);
550 '- Membership period overlaps period starting at ' . $now->format('Y-m-d')
555 $this->expectException('RuntimeException');
556 $this->expectExceptionMessage('Existing errors prevents storing contribution');
557 $store = $contrib->store();
565 public function testGetFieldLabel()
569 $this->contrib
->getFieldLabel('montant_cotis')
573 'Date of contribution',
574 $this->contrib
->getFieldLabel('date_debut_cotis')
577 $this->contrib
->type
= 1;
579 'Start date of membership',
580 $this->contrib
->getFieldLabel('date_debut_cotis')
585 $this->contrib
->getFieldLabel('info_cotis')
590 * Test contribution loading
594 public function testLoad()
596 $this->login
= $this->getMockBuilder(\Galette\Core\Login
::class)
597 ->setConstructorArgs(array($this->zdb
, $this->i18n
))
598 ->onlyMethods(array('isLogged', 'isStaff', 'isAdmin'))
600 $this->login
->method('isLogged')->willReturn(true);
601 $this->login
->method('isStaff')->willReturn(true);
602 $this->login
->method('isAdmin')->willReturn(true);
604 $this->getMemberOne();
606 //create contribution for member
607 $this->createContribution();
609 $id = $this->contrib
->id
;
610 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
612 $this->assertTrue($contrib->load((int)$id));
613 $this->checkContribExpected($contrib);
615 $this->assertFalse($contrib->load(1355522012));
619 * Test contribution removal
623 public function testRemove()
625 $this->getMemberOne();
626 $this->createContribution();
628 $this->assertTrue($this->contrib
->remove());
629 $this->assertFalse($this->contrib
->remove());
637 public function testCan()
639 $this->getMemberOne();
640 //create contribution for member
641 $this->createContribution();
642 $contrib = $this->contrib
;
644 $this->assertFalse($contrib->canShow($this->login
));
646 //Superadmin can fully change contributions
647 $this->logSuperAdmin();
649 $this->assertTrue($contrib->canShow($this->login
));
652 $this->login
->logOut();
653 $this->assertFalse($this->login
->isLogged());
655 //Member can fully change its own contributions
656 $mdata = $this->dataAdherentOne();
657 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
658 $this->assertTrue($this->login
->isLogged());
659 $this->assertFalse($this->login
->isAdmin());
660 $this->assertFalse($this->login
->isStaff());
662 $this->assertTrue($contrib->canShow($this->login
));
665 $this->login
->logOut();
666 $this->assertFalse($this->login
->isLogged());
668 //Another member has no access
669 $this->getMemberTwo();
670 $mdata = $this->dataAdherentTwo();
671 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
672 $this->assertTrue($this->login
->isLogged());
673 $this->assertFalse($this->login
->isAdmin());
674 $this->assertFalse($this->login
->isStaff());
676 $this->assertFalse($contrib->canShow($this->login
));
678 //parents can chow change children contributions
679 $this->getMemberOne();
680 $member = $this->adh
;
681 $mdata = $this->dataAdherentOne();
683 $login = $this->login
;
684 $this->logSuperAdmin();
688 'prenom_adh' => 'Johny',
689 'parent_id' => $member->id
,
691 'login_adh' => 'child.johny.doe',
692 'fingerprint' => 'FAKER' . $this->seed
694 $child = $this->createMember($child_data);
697 //contribution for child
698 $begin_date = new \
DateTime(); // 2020-11-07
699 $begin_date->sub(new \
DateInterval('P5M')); // 2020-06-07
700 $begin_date->add(new \
DateInterval('P3D')); // 2020-06-10
702 $due_date = clone $begin_date;
703 $due_date->add(new \
DateInterval('P1Y'));
704 $due_date->sub(new \
DateInterval('P1D'));
708 'id_type_cotis' => 1,
709 'montant_cotis' => 25,
710 'type_paiement_cotis' => 3,
711 'info_cotis' => 'FAKER' . $this->seed
,
712 'date_enreg' => $begin_date->format('Y-m-d'),
713 'date_debut_cotis' => $begin_date->format('Y-m-d'),
714 'date_fin_cotis' => $due_date->format('Y-m-d'),
716 $ccontrib = $this->createContrib($data);
718 $this->login
->logOut();
721 $child = new \Galette\Entity\
Adherent($this->zdb
);
722 $child->enableDep('parent');
723 $this->assertTrue($child->load($cid));
725 $this->assertSame($child_data['nom_adh'], $child->name
);
726 $this->assertInstanceOf('\Galette\Entity\Adherent', $child->parent
);
727 $this->assertSame($member->id
, $child->parent
->id
);
728 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
730 $mdata = $this->dataAdherentOne();
731 $this->assertTrue($this->login
->login($mdata['login_adh'], $mdata['mdp_adh']));
732 $this->assertTrue($this->login
->isLogged());
733 $this->assertFalse($this->login
->isAdmin());
734 $this->assertFalse($this->login
->isStaff());
736 $this->assertTrue($ccontrib->canShow($this->login
));
739 $this->login
->logOut();
740 $this->assertFalse($this->login
->isLogged());