]> git.agnieray.net Git - galette.git/blob - tests/Galette/Entity/tests/units/Contribution.php
f3f2ae60dfeb6c43b256e4462411e159f56bcb25
[galette.git] / tests / Galette / Entity / tests / units / Contribution.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Contribution tests
7 *
8 * PHP version 5
9 *
10 * Copyright © 2017 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
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.
18 *
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.
23 *
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/>.
26 *
27 * @category Entity
28 * @package GaletteTests
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2017 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 * @version SVN: $Id$
34 * @link http://galette.tuxfamily.org
35 * @since 2017-06-11
36 */
37
38 namespace Galette\Entity\test\units;
39
40 use Galette\GaletteTestCase;
41
42 /**
43 * Contribution tests class
44 *
45 * @category Entity
46 * @name Contribution
47 * @package GaletteTests
48 * @author Johan Cwiklinski <johan@x-tnd.be>
49 * @copyright 2017 The Galette Team
50 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
51 * @link http://galette.tuxfamily.org
52 * @since 2017-06-11
53 */
54 class Contribution extends GaletteTestCase
55 {
56 protected $seed = 95842354;
57
58 /**
59 * Cleanup after each test method
60 *
61 * @param string $method Calling method
62 *
63 * @return void
64 */
65 public function afterTestMethod($method)
66 {
67 $this->zdb = new \Galette\Core\Db();
68 $delete = $this->zdb->delete(\Galette\Entity\Contribution::TABLE);
69 $delete->where(['info_cotis' => 'FAKER' . $this->seed]);
70 $this->zdb->execute($delete);
71
72 $delete = $this->zdb->delete(\Galette\Entity\Adherent::TABLE);
73 $delete->where(['fingerprint' => 'FAKER' . $this->seed]);
74 $delete->where('parent_id IS NOT NULL');
75 $this->zdb->execute($delete);
76
77 $delete = $this->zdb->delete(\Galette\Entity\Adherent::TABLE);
78 $delete->where(['fingerprint' => 'FAKER' . $this->seed]);
79 $this->zdb->execute($delete);
80
81 $this->cleanHistory();
82 }
83
84 /**
85 * Set up tests
86 *
87 * @param string $testMethod Calling method
88 *
89 * @return void
90 */
91 public function beforeTestMethod($testMethod)
92 {
93 parent::beforeTestMethod($testMethod);
94 $this->initContributionsTypes();
95
96 $this->contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
97
98 $this->adh = new \Galette\Entity\Adherent($this->zdb);
99 $this->adh->setDependencies(
100 $this->preferences,
101 $this->members_fields,
102 $this->history
103 );
104 }
105
106 /**
107 * Test empty contribution
108 *
109 * @return void
110 */
111 public function testEmpty()
112 {
113 $contrib = $this->contrib;
114 $this->variable($contrib->id)->isNull();
115 $this->variable($contrib->isFee())->isNull();
116 $this->variable($contrib->is_cotis)->isNull();
117 $this->variable($contrib->date)->isNull();
118 $this->variable($contrib->begin_date)->isNull();
119 $this->variable($contrib->end_date)->isNull();
120 $this->variable($contrib->raw_date)->isNull();
121 $this->variable($contrib->raw_begin_date)->isNull();
122 $this->variable($contrib->raw_end_date)->isNull();
123 $this->string($contrib->duration)->isEmpty();
124 $this->variable($contrib->payment_type)->isIdenticalTo((int)$this->preferences->pref_default_paymenttype);
125 $this->string($contrib->spayment_type)->isIdenticalTo('Check');
126 $this->variable($contrib->model)->isNull();
127 $this->variable($contrib->member)->isNull();
128 $this->variable($contrib->type)->isNull();
129 $this->variable($contrib->amount)->isNull();
130 $this->variable($contrib->orig_amount)->isNull();
131 $this->variable($contrib->info)->isNull();
132 $this->variable($contrib->transaction)->isNull();
133 $this->array($contrib->fields)
134 ->hasSize(11)
135 ->hasKeys([
136 \Galette\Entity\Contribution::PK,
137 \Galette\Entity\Adherent::PK,
138 \Galette\Entity\ContributionsTypes::PK,
139 'montant_cotis',
140 'type_paiement_cotis',
141 'info_cotis',
142 'date_debut_cotis'
143 ]);
144
145 $this->string($contrib->getRowClass())->isIdenticalTo('cotis-give');
146 $this->variable($contrib::getDueDate($this->zdb, 1))->isNull();
147 $this->boolean($contrib->isTransactionPart())->isFalse();
148 $this->boolean($contrib->isTransactionPartOf(1))->isFalse();
149 $this->string($contrib->getRawType())->isIdenticalTo('donation');
150 $this->string($contrib->getTypeLabel())->isIdenticalTo('Donation');
151 $this->string($contrib->getPaymentType())->isIdenticalTo('Check');
152 $this->variable($contrib->unknown_property)->isNull();
153 }
154
155 /**
156 * Test getter and setter special cases
157 *
158 * @return void
159 */
160 public function testGetterSetter()
161 {
162 $contrib = $this->contrib;
163
164 //set a bad date
165 $contrib->begin_date = 'not a date';
166 $this->variable($contrib->raw_begin_date)->isNull();
167 $this->variable($contrib->begin_date)->isNull();
168
169 $contrib->begin_date = '2017-06-17';
170 $this->object($contrib->raw_begin_date)->isInstanceOf('DateTime');
171 $this->string($contrib->begin_date)->isIdenticalTo('2017-06-17');
172
173 $contrib->amount = 'not an amount';
174 $this->variable($contrib->amount)->isNull();
175 $contrib->amount = 0;
176 $this->variable($contrib->amount)->isNull();
177 $contrib->amount = 42;
178 $this->integer($contrib->amount)->isIdenticalTo(42);
179 $contrib->amount = '42';
180 $this->string($contrib->amount)->isIdenticalTo('42');
181
182 $contrib->type = 'not a type';
183 $this->variable($contrib->type)->isNull();
184 $contrib->type = 156;
185 $this->object($contrib->type)->isInstanceOf('\Galette\Entity\ContributionsTypes');
186 $this->boolean($contrib->type->id)->isFalse();
187 $contrib->type = 1;
188 $this->object($contrib->type)->isInstanceOf('\Galette\Entity\ContributionsTypes');
189 $this->variable($contrib->type->id)->isEqualTo(1);
190
191 $contrib->transaction = 'not a transaction id';
192 $this->variable($contrib->transaction)->isNull();
193 $contrib->transaction = 46;
194 $this->object($contrib->transaction)->isInstanceOf('\Galette\Entity\Transaction');
195 $this->variable($contrib->transaction->id)->isNull();
196
197 $contrib->member = 'not a member';
198 $this->variable($contrib->member)->isNull();
199 $contrib->member = 118218;
200 $this->integer($contrib->member)->isIdenticalTo(118218);
201
202 $contrib->not_a_property = 'abcde';
203 $this->boolean(property_exists($contrib, 'not_a_property'))->isFalse();
204
205 $contrib->payment_type = \Galette\Entity\PaymentType::CASH;
206 $this->string($contrib->getPaymentType())->isIdenticalTo('Cash');
207 $this->string($contrib->spayment_type)->isIdenticalTo('Cash');
208
209 $contrib->payment_type = \Galette\Entity\PaymentType::CHECK;
210 $this->string($contrib->getPaymentType())->isIdenticalTo('Check');
211 $this->string($contrib->spayment_type)->isIdenticalTo('Check');
212
213 $contrib->payment_type = \Galette\Entity\PaymentType::OTHER;
214 $this->string($contrib->getPaymentType())->isIdenticalTo('Other');
215 $this->string($contrib->spayment_type)->isIdenticalTo('Other');
216
217 $contrib->payment_type = \Galette\Entity\PaymentType::CREDITCARD;
218 $this->string($contrib->getPaymentType())->isIdenticalTo('Credit card');
219 $this->string($contrib->spayment_type)->isIdenticalTo('Credit card');
220
221 $contrib->payment_type = \Galette\Entity\PaymentType::TRANSFER;
222 $this->string($contrib->getPaymentType())->isIdenticalTo('Transfer');
223 $this->string($contrib->spayment_type)->isIdenticalTo('Transfer');
224
225 $contrib->payment_type = \Galette\Entity\PaymentType::PAYPAL;
226 $this->string($contrib->getPaymentType())->isIdenticalTo('Paypal');
227 $this->string($contrib->spayment_type)->isIdenticalTo('Paypal');
228 }
229
230 /**
231 * Test contribution creation
232 *
233 * @return void
234 */
235 public function testCreation()
236 {
237 $this->getMemberOne();
238 //create contribution for member
239 $this->createContribution();
240 }
241
242 /**
243 * Test contribution update
244 *
245 * @return void
246 */
247 public function testUpdate()
248 {
249 $this->getMemberOne();
250 //create contribution for member
251 $bdate = new \DateTime(); // 2020-11-07
252 $bdate->sub(new \DateInterval('P5M')); // 2020-06-07
253 $bdate->add(new \DateInterval('P3D')); // 2020-06-10
254
255 $edate = clone $bdate;
256 $edate->add(new \DateInterval('P1Y'));
257
258 $data = [
259 'id_adh' => $this->adh->id,
260 'id_type_cotis' => 4, //donation
261 'montant_cotis' => 12,
262 'type_paiement_cotis' => 3,
263 'info_cotis' => 'FAKER' . $this->seed,
264 'date_enreg' => $bdate->format('Y-m-d'),
265 'date_debut_cotis' => $bdate->format('Y-m-d'),
266 'date_fin_cotis' => $edate->format('Y-m-d'),
267 ];
268 $this->createContrib($data);
269 $this->array($this->contrib->getRequired())->isIdenticalTo([
270 'id_type_cotis' => 1,
271 'id_adh' => 1,
272 'date_enreg' => 1,
273 'date_debut_cotis' => 1,
274 'date_fin_cotis' => 0,
275 'montant_cotis' => 0
276 ]);
277
278 $this->logSuperAdmin();
279 $data = [
280 'id_adh' => $this->adh->id,
281 'id_type_cotis' => 4, //donation
282 'montant_cotis' => 1280,
283 'type_paiement_cotis' => 4,
284 'info_cotis' => 'FAKER' . $this->seed,
285 'date_enreg' => $bdate->format('Y-m-d'),
286 'date_debut_cotis' => $bdate->format('Y-m-d'),
287 'date_fin_cotis' => $edate->format('Y-m-d'),
288
289 ];
290 $check = $this->contrib->check($data, [], []);
291 if (is_array($check)) {
292 var_dump($check);
293 }
294 $this->boolean($check)->isTrue();
295
296 $store = $this->contrib->store();
297 $this->boolean($store)->isTrue();
298
299 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login, $this->contrib->id);
300 $this->variable($contrib->amount)->isIdenticalTo(1280);
301 }
302
303 /**
304 * Test end date retrieving
305 * This is based on some Preferences parameters
306 *
307 * @return void
308 */
309 public function testRetrieveEndDate()
310 {
311 global $preferences;
312 $orig_pref_beg_membership = $this->preferences->pref_beg_membership;
313 $orig_pref_membership_ext = $this->preferences->pref_membership_ext;
314 $orig_pref_membership_offermonths = $this->preferences->pref_membership_offermonths;
315
316 $contrib = new \Galette\Entity\Contribution(
317 $this->zdb,
318 $this->login,
319 ['type' => 1] //annual fee
320 );
321
322 // First, check for 12 months renewal
323 $expected = new \DateTime();
324 $expected->add(new \DateInterval('P1Y'));
325 $this->string($contrib->end_date)->isIdenticalTo($expected->format('Y-m-d'));
326
327 //unset pref_beg_membership and pref_membership_ext
328 $preferences->pref_beg_membership = '';
329 $preferences->pref_membership_ext = '';
330
331 $this->exception(
332 function () {
333 $contrib = new \Galette\Entity\Contribution(
334 $this->zdb,
335 $this->login,
336 ['type' => 1] //annual fee
337 );
338 }
339 )
340 ->isInstanceOf('RuntimeException')
341 ->hasMessage('Unable to define end date; none of pref_beg_membership nor pref_membership_ext are defined!');
342
343 // Second, test with beginning of membership date
344 $preferences->pref_beg_membership = '29/05';
345 $expected = new \DateTime();
346 $expected->setDate(date('Y'), 5, 29);
347 if ($expected < new \DateTime()) {
348 $expected->add(new \DateInterval('P1Y'));
349 }
350
351 $contrib = new \Galette\Entity\Contribution(
352 $this->zdb,
353 $this->login,
354 ['type' => 1] // annual fee
355 );
356 $this->string($contrib->end_date)->isIdenticalTo($expected->format('Y-m-d'));
357
358 // Third, test with beginning of membership date and i2 last months offered
359 $beginning = new \DateTime();
360 $beginning->add(new \DateInterval('P1M'));
361 $preferences->pref_beg_membership = $beginning->format('t/m'); // end of next month
362 $preferences->pref_membership_offermonths = 2;
363 $expected = clone $beginning;
364 $expected->add(new \DateInterval('P1Y'));
365
366 $contrib = new \Galette\Entity\Contribution(
367 $this->zdb,
368 $this->login,
369 ['type' => 1] // annual fee
370 );
371 $this->string($contrib->end_date)->isIdenticalTo($expected->format('Y-m-t'));
372
373 //reset
374 $preferences->pref_beg_membership = $orig_pref_beg_membership;
375 $preferences->pref_membership_ext = $orig_pref_membership_ext;
376 $preferences->pref_membership_offermonths = $orig_pref_membership_offermonths;
377 }
378
379 /**
380 * Test checkOverlap method
381 *
382 * @return void
383 */
384 public function testCheckOverlap()
385 {
386 $adh = new \Galette\Entity\Adherent($this->zdb);
387 $adh->setDependencies(
388 $this->preferences,
389 $this->members_fields,
390 $this->history
391 );
392
393 $check = $adh->check(
394 [
395 'nom_adh' => 'Overlapped',
396 'date_crea_adh' => date(_T("Y-m-d")),
397 \Galette\Entity\Status::PK => \Galette\Entity\Status::DEFAULT_STATUS,
398 'fingerprint' => 'FAKER' . $this->seed
399 ],
400 [],
401 []
402 );
403 if (is_array($check)) {
404 var_dump($check);
405 }
406 $this->boolean($check)->isTrue();
407
408 $store = $adh->store();
409 $this->boolean($store)->isTrue();
410
411 //create first contribution for member
412 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
413
414 $now = new \DateTime();
415 $end_date = clone $now;
416 $end_date->add(new \DateInterval('P1Y'));
417 $data = [
418 \Galette\Entity\Adherent::PK => $adh->id,
419 \Galette\Entity\ContributionsTypes::PK => 1, //annual fee
420 'montant_cotis' => 20,
421 'type_paiement_cotis' => \Galette\Entity\PaymentType::CHECK,
422 'date_enreg' => $now->format(_T("Y-m-d")),
423 'date_debut_cotis' => $now->format(_T("Y-m-d")),
424 'date_fin_cotis' => $end_date->format(_T("Y-m-d")),
425 'info_cotis' => 'FAKER' . $this->seed
426 ];
427
428 $check = $contrib->check($data, [], []);
429 if (is_array($check)) {
430 var_dump($check);
431 }
432 $this->boolean($check)->isTrue();
433 $this->boolean($contrib->checkOverlap())->isTrue();
434
435 $store = $contrib->store();
436 $this->boolean($store)->isTrue();
437
438 //load member from db
439 $adh = new \Galette\Entity\Adherent($this->zdb, $adh->id);
440
441 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
442 $begin = clone $end_date;
443 $begin->sub(new \DateInterval('P3M'));
444 $end_date = clone $begin;
445 $end_date->add(new \DateInterval('P1Y'));
446 $data = [
447 \Galette\Entity\Adherent::PK => $adh->id,
448 \Galette\Entity\ContributionsTypes::PK => 1, //anunal fee
449 'montant_cotis' => 20,
450 'type_paiement_cotis' => \Galette\Entity\PaymentType::CHECK,
451 'date_enreg' => $now->format(_T("Y-m-d")),
452 'date_debut_cotis' => $begin->format(_T("Y-m-d")),
453 'date_fin_cotis' => $end_date->format(_T("Y-m-d")),
454 'info_cotis' => 'FAKER' . $this->seed
455 ];
456
457 $check = $contrib->check($data, [], []);
458 $this->array($check)->isIdenticalTo([
459 '- Membership period overlaps period starting at ' . $now->format('Y-m-d')
460 ]);
461
462 $this->exception(
463 function () use ($contrib) {
464 $store = $contrib->store();
465 }
466 )
467 ->isInstanceOf('RuntimeException')
468 ->message->startWith('Existing errors prevents storing contribution');
469 }
470
471 /**
472 * Test checkOverlap method that throws an exception
473 *
474 * @return void
475 */
476 public function testCheckOverlapWException()
477 {
478 $zdb = new \mock\Galette\Core\Db();
479 $this->calling($zdb)->execute = function ($o) {
480 if ($o instanceof \Zend\Db\Sql\Select) {
481 throw new \LogicException('Error executing query!', 123);
482 }
483 };
484
485 $contrib = new \Galette\Entity\Contribution($zdb, $this->login);
486 $this->boolean($contrib->checkOverlap())->isFalse();
487 }
488
489
490 /**
491 * Test fields labels
492 *
493 * @return void
494 */
495 public function testGetFieldLabel()
496 {
497 $this->string($this->contrib->getFieldLabel('montant_cotis'))
498 ->isIdenticalTo('Amount');
499
500 $this->string($this->contrib->getFieldLabel('date_debut_cotis'))
501 ->isIdenticalTo('Date of contribution');
502
503 $this->contrib->type = 1;
504 $this->string($this->contrib->getFieldLabel('date_debut_cotis'))
505 ->isIdenticalTo('Start date of membership');
506
507 $this->string($this->contrib->getFieldLabel('info_cotis'))
508 ->isIdenticalTo('Comments');
509 }
510
511 /**
512 * Test contribution loading
513 *
514 * @return void
515 */
516 public function testLoad()
517 {
518 $this->login = new \mock\Galette\Core\Login($this->zdb, $this->i18n);
519 $this->calling($this->login)->isLogged = true;
520 $this->calling($this->login)->isStaff = true;
521 $this->calling($this->login)->isAdmin = true;
522
523 $this->getMemberOne();
524
525 //create contribution for member
526 $this->createContribution();
527
528 $id = $this->contrib->id;
529 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
530
531 $this->boolean($contrib->load((int)$id))->isTrue();
532 $this->checkContribExpected($contrib);
533
534 $this->boolean($contrib->load(1355522012))->isFalse();
535 }
536
537 /**
538 * Test contribution removal
539 *
540 * @return void
541 */
542 public function testRemove()
543 {
544 $this->getMemberOne();
545 $this->createContribution();
546
547 $this->boolean($this->contrib->remove())->isTrue();
548
549 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
550 $this->boolean($this->contrib->remove())->isFalse();
551 }
552
553 /**
554 * Test can* methods
555 *
556 * @return void
557 */
558 public function testCan()
559 {
560 $this->getMemberOne();
561 //create contribution for member
562 $this->createContribution();
563 $contrib = $this->contrib;
564
565 $this->boolean($contrib->canShow($this->login))->isFalse();
566
567 //Superadmin can fully change contributions
568 $this->logSuperAdmin();
569
570 $this->boolean($contrib->canShow($this->login))->isTrue();
571
572 //logout
573 $this->login->logOut();
574 $this->boolean($this->login->isLogged())->isFalse();
575
576 //Member can fully change its own contributions
577 $mdata = $this->dataAdherentOne();
578 $this->boolean($this->login->login($mdata['login_adh'], $mdata['mdp_adh']))->isTrue();
579 $this->boolean($this->login->isLogged())->isTrue();
580 $this->boolean($this->login->isAdmin())->isFalse();
581 $this->boolean($this->login->isStaff())->isFalse();
582
583 $this->boolean($contrib->canShow($this->login))->isTrue();
584
585 //logout
586 $this->login->logOut();
587 $this->boolean($this->login->isLogged())->isFalse();
588
589 //Another member has no access
590 $this->getMemberTwo();
591 $mdata = $this->dataAdherentTwo();
592 $this->boolean($this->login->login($mdata['login_adh'], $mdata['mdp_adh']))->isTrue();
593 $this->boolean($this->login->isLogged())->isTrue();
594 $this->boolean($this->login->isAdmin())->isFalse();
595 $this->boolean($this->login->isStaff())->isFalse();
596
597 $this->boolean($contrib->canShow($this->login))->isFalse();
598
599 //parents can chow change children contributions
600 $this->getMemberOne();
601 $member = $this->adh;
602 $mdata = $this->dataAdherentOne();
603 global $login;
604 $login = $this->login;
605 $this->logSuperAdmin();
606
607 $child_data = [
608 'nom_adh' => 'Doe',
609 'prenom_adh' => 'Johny',
610 'parent_id' => $member->id,
611 'attach' => true,
612 'login_adh' => 'child.johny.doe',
613 'fingerprint' => 'FAKER' . $this->seed
614 ];
615 $child = $this->createMember($child_data);
616 $cid = $child->id;
617
618 //contribution for child
619 $bdate = new \DateTime(); // 2020-11-07
620 $bdate->sub(new \DateInterval('P5M')); // 2020-06-07
621 $bdate->add(new \DateInterval('P3D')); // 2020-06-10
622
623 $edate = clone $bdate;
624 $edate->add(new \DateInterval('P1Y'));
625
626 $data = [
627 'id_adh' => $cid,
628 'id_type_cotis' => 1,
629 'montant_cotis' => 25,
630 'type_paiement_cotis' => 3,
631 'info_cotis' => 'FAKER' . $this->seed,
632 'date_enreg' => $bdate->format('Y-m-d'),
633 'date_debut_cotis' => $bdate->format('Y-m-d'),
634 'date_fin_cotis' => $edate->format('Y-m-d'),
635 ];
636 $ccontrib = $this->createContrib($data);
637
638 $this->login->logOut();
639
640 //load child from db
641 $child = new \Galette\Entity\Adherent($this->zdb);
642 $child->enableDep('parent');
643 $this->boolean($child->load($cid))->isTrue();
644
645 $this->string($child->name)->isIdenticalTo($child_data['nom_adh']);
646 $this->object($child->parent)->isInstanceOf('\Galette\Entity\Adherent');
647 $this->integer($child->parent->id)->isIdenticalTo($member->id);
648 $this->boolean($this->login->login($mdata['login_adh'], $mdata['mdp_adh']))->isTrue();
649
650 $mdata = $this->dataAdherentOne();
651 $this->boolean($this->login->login($mdata['login_adh'], $mdata['mdp_adh']))->isTrue();
652 $this->boolean($this->login->isLogged())->isTrue();
653 $this->boolean($this->login->isAdmin())->isFalse();
654 $this->boolean($this->login->isStaff())->isFalse();
655
656 $this->boolean($ccontrib->canShow($this->login))->isTrue();
657
658 //logout
659 $this->login->logOut();
660 $this->boolean($this->login->isLogged())->isFalse();
661 }
662 }