3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
10 * Copyright © 2017 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 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
34 * @link http://galette.tuxfamily.org
38 namespace Galette\Entity\test\units
;
43 * Contribution tests class
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
54 class Contribution
extends atoum
62 private $seed = 95842354;
63 private $default_deps;
67 private $members_fields;
74 public function setUp()
76 $this->zdb
= new \Galette\Core\
Db();
77 $ct = new \Galette\Entity\
ContributionsTypes($this->zdb
);
78 if (count($ct->getCompleteList()) === 0) {
79 //status are not yet instanciated.
80 $res = $ct->installInit();
81 $this->boolean($res)->isTrue();
86 * Cleanup after testeach test method
88 * @param string $method Calling method
92 public function afterTestMethod($method)
94 $this->zdb
= new \Galette\Core\
Db();
95 $delete = $this->zdb
->delete(\Galette\Entity\Contribution
::TABLE
);
96 $delete->where(['info_cotis' => 'FAKER' . $this->seed
]);
97 $this->zdb
->execute($delete);
98 $delete = $this->zdb
->delete(\Galette\Entity\Adherent
::TABLE
);
99 $delete->where(['fingerprint' => 'FAKER' . $this->seed
]);
100 $this->zdb
->execute($delete);
106 * @param string $testMethod Calling method
110 public function beforeTestMethod($testMethod)
112 $this->zdb
= new \Galette\Core\
Db();
114 $this->i18n
= new \Galette\Core\
I18n(
115 \Galette\Core\I18n
::DEFAULT_LANG
118 $this->preferences
= new \Galette\Core\
Preferences(
121 $this->session
= new \RKA\
Session();
122 $this->login
= new \Galette\Core\
Login($this->zdb
, $this->i18n
, $this->session
);
123 $this->history
= new \Galette\Core\
History($this->zdb
, $this->login
);
125 global $zdb, $login, $hist, $i18n; // globals :(
127 $login = $this->login
;
128 $hist = $this->history
;
131 $this->contrib
= new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
133 include_once GALETTE_ROOT
. 'includes/fields_defs/members_fields.php';
134 $this->members_fields
= $members_fields;
135 $this->adh
= new \Galette\Entity\
Adherent($this->zdb
);
136 $this->adh
->setDependencies(
138 $this->members_fields
,
144 * Create test user in database
148 private function createAdherent()
150 $fakedata = new \Galette\Util\
FakeData($this->zdb
, $this->i18n
);
152 ->setSeed($this->seed
)
155 $this->members_fields
,
160 $data = $fakedata->fakeMember();
161 $this->createMember($data);
162 $this->checkMemberExpected();
166 * Create test contribution in database
170 private function createContribution()
172 $fakedata = new \Galette\Util\
FakeData($this->zdb
, $this->i18n
);
174 ->setSeed($this->seed
)
177 $this->members_fields
,
182 $data = $fakedata->fakeContrib($this->adh
->id
);
183 $this->createContrib($data);
184 $this->checkContribExpected();
188 * Loads member from a resultset
190 * @param ResultSet $rs ResultSet
194 private function loadAdherent($rs)
196 $this->adh
= new \Galette\Entity\
Adherent($this->zdb
, $rs);
200 * Loads contribution from a resultset
202 * @param ResultSet $rs ResultSet
206 private function loadContribution($rs)
208 $this->adh
= new \Galette\Entity\
Contribution($this->zdb
, $this->login
, $rs);
213 * Test empty contribution
217 public function testEmpty()
219 $contrib = $this->contrib
;
220 $this->variable($contrib->id
)->isNull();
221 $this->variable($contrib->isCotis())->isNull();
222 $this->variable($contrib->is_cotis
)->isNull();
223 $this->variable($contrib->date
)->isNull();
224 $this->variable($contrib->begin_date
)->isNull();
225 $this->variable($contrib->end_date
)->isNull();
226 $this->variable($contrib->raw_date
)->isNull();
227 $this->variable($contrib->raw_begin_date
)->isNull();
228 $this->variable($contrib->raw_end_date
)->isNull();
229 $this->string($contrib->duration
)->isEmpty();
230 $this->variable($contrib->payment_type
)->isNull();
231 $this->string($contrib->spayment_type
)->isIdenticalTo('-');
232 $this->variable($contrib->model
)->isNull();
233 $this->variable($contrib->member
)->isNull();
234 $this->variable($contrib->type
)->isNull();
235 $this->variable($contrib->amount
)->isNull();
236 $this->variable($contrib->orig_amount
)->isNull();
237 $this->variable($contrib->info
)->isNull();
238 $this->variable($contrib->transaction
)->isNull();
239 $this->array($contrib->fields
)
242 \Galette\Entity\Contribution
::PK
,
243 \Galette\Entity\Adherent
::PK
,
244 \Galette\Entity\ContributionsTypes
::PK
,
246 'type_paiement_cotis',
251 $this->string($contrib->getRowClass())->isIdenticalTo('cotis-give');
252 $this->variable($contrib::getDueDate($this->zdb
, 1))->isNull();
253 $this->boolean($contrib->isTransactionPart())->isFalse();
254 $this->boolean($contrib->isTransactionPartOf(1))->isFalse();
255 $this->string($contrib->getRawType())->isIdenticalTo('donation');
256 $this->string($contrib->getTypeLabel())->isIdenticalTo('Donation');
257 $this->string($contrib->getPaymentType())->isIdenticalTo('-');
258 $this->variable($contrib->unknown_property
)->isNull();
262 * Test getter and setter special cases
266 public function testGetterSetter()
268 $contrib = $this->contrib
;
271 $contrib->begin_date
= 'not a date';
272 $this->variable($contrib->raw_begin_date
)->isNull();
273 $this->variable($contrib->begin_date
)->isNull();
275 $contrib->begin_date
= '2017-06-17';
276 $this->object($contrib->raw_begin_date
)->isInstanceOf('DateTime');
277 $this->string($contrib->begin_date
)->isIdenticalTo('2017-06-17');
279 $contrib->amount
= 'not an amount';
280 $this->variable($contrib->amount
)->isNull();
281 $contrib->amount
= 0;
282 $this->variable($contrib->amount
)->isNull();
283 $contrib->amount
= 42;
284 $this->integer($contrib->amount
)->isIdenticalTo(42);
285 $contrib->amount
= '42';
286 $this->string($contrib->amount
)->isIdenticalTo('42');
288 $contrib->type
= 'not a type';
289 $this->variable($contrib->type
)->isNull();
290 $contrib->type
= 156;
291 $this->object($contrib->type
)->isInstanceOf('\Galette\Entity\ContributionsTypes');
292 $this->boolean($contrib->type
->id
)->isFalse();
294 $this->object($contrib->type
)->isInstanceOf('\Galette\Entity\ContributionsTypes');
295 $this->variable($contrib->type
->id
)->isEqualTo(1);
297 $contrib->transaction
= 'not a transaction id';
298 $this->variable($contrib->transaction
)->isNull();
299 $contrib->transaction
= 46;
300 $this->object($contrib->transaction
)->isInstanceOf('\Galette\Entity\Transaction');
301 $this->boolean($contrib->transaction
->id
)->isFalse();
303 $contrib->member
= 'not a member';
304 $this->variable($contrib->member
)->isNull();
305 $contrib->member
= 118218;
306 $this->integer($contrib->member
)->isIdenticalTo(118218);
308 $contrib->not_a_property
= 'abcde';
309 $this->boolean(property_exists($contrib, 'not_a_property'))->isFalse();
311 $contrib->payment_type
= \Galette\Entity\PaymentType
::CASH
;
312 $this->string($contrib->getPaymentType())->isIdenticalTo('Cash');
313 $this->string($contrib->spayment_type
)->isIdenticalTo('Cash');
315 $contrib->payment_type
= \Galette\Entity\PaymentType
::CHECK
;
316 $this->string($contrib->getPaymentType())->isIdenticalTo('Check');
317 $this->string($contrib->spayment_type
)->isIdenticalTo('Check');
319 $contrib->payment_type
= \Galette\Entity\PaymentType
::OTHER
;
320 $this->string($contrib->getPaymentType())->isIdenticalTo('Other');
321 $this->string($contrib->spayment_type
)->isIdenticalTo('Other');
323 $contrib->payment_type
= \Galette\Entity\PaymentType
::CREDITCARD
;
324 $this->string($contrib->getPaymentType())->isIdenticalTo('Credit card');
325 $this->string($contrib->spayment_type
)->isIdenticalTo('Credit card');
327 $contrib->payment_type
= \Galette\Entity\PaymentType
::TRANSFER
;
328 $this->string($contrib->getPaymentType())->isIdenticalTo('Transfer');
329 $this->string($contrib->spayment_type
)->isIdenticalTo('Transfer');
331 $contrib->payment_type
= \Galette\Entity\PaymentType
::PAYPAL
;
332 $this->string($contrib->getPaymentType())->isIdenticalTo('Paypal');
333 $this->string($contrib->spayment_type
)->isIdenticalTo('Paypal');
337 * Create member from data
339 * @param array $data Data to use to create member
341 * @return \Galette\Entity\Adherent
343 public function createMember(array $data)
346 $check = $adh->check($data, [], []);
347 if (is_array($check)) {
350 $this->boolean($check)->isTrue();
352 $store = $adh->store();
353 $this->boolean($store)->isTrue();
355 $this->ids
[] = $adh->id
;
359 * Create contribution from data
361 * @param array $data Data to use to create contribution
363 * @return \Galette\Entity\Contribution
365 public function createContrib(array $data)
367 $contrib = $this->contrib
;
368 $check = $contrib->check($data, [], []);
369 if (is_array($check)) {
372 $this->boolean($check)->isTrue();
374 $store = $contrib->store();
375 $this->boolean($store)->isTrue();
377 $this->ids
[] = $contrib->id
;
382 * Check members expecteds
384 * @param Adherent $adh Member instance, if any
385 * @param array $new_expecteds Changes on expected values
389 private function checkMemberExpected($adh = null, $new_expecteds = [])
396 'nom_adh' => 'Durand',
397 'prenom_adh' => 'René',
398 'ville_adh' => 'Martel',
399 'cp_adh' => '07 926',
400 'adresse_adh' => '66, boulevard De Oliveira',
401 'email_adh' => 'meunier.josephine@ledoux.com',
402 'login_adh' => 'arthur.hamon',
403 'mdp_adh' => 'J^B-()f',
404 'bool_admin_adh' => false,
405 'bool_exempt_adh' => false,
406 'bool_display_info' => true,
408 'prof_adh' => 'Chef de fabrication',
410 'ddn_adh' => '1934-06-08',
411 'lieu_naissance' => 'Gonzalez-sur-Meunier',
412 'pseudo_adh' => 'ubertrand',
413 'cp_adh' => '39 069',
414 'pays_adh' => 'Antarctique',
415 'tel_adh' => '0439153432',
416 'url_adh' => 'http://bouchet.com/',
417 'activite_adh' => true,
419 'pref_lang' => 'en_US',
420 'fingerprint' => 'FAKER' . $this->seed
,
423 $expecteds = array_merge($expecteds, $new_expecteds);
425 foreach ($expecteds as $key => $value) {
426 $property = $this->members_fields
[$key]['propname'];
428 case 'bool_admin_adh':
429 $this->boolean($adh->isAdmin())->isIdenticalTo($value);
431 case 'bool_exempt_adh':
432 $this->boolean($adh->isDueFree())->isIdenticalTo($value);
434 case 'bool_display_info':
435 $this->boolean($adh->appearsInMembersList())->isIdenticalTo($value);
438 $this->boolean($adh->isActive())->isIdenticalTo($value);
441 $pw_checked = password_verify($value, $adh->password
);
442 $this->boolean($pw_checked)->isTrue();
445 //rely on age, not on birthdate
446 $this->variable($adh->$property)->isNotNull();
447 $this->string($adh->getAge())->isIdenticalTo(' (82 years old)');
450 $this->variable($adh->$property)->isIdenticalTo($value, $property);
455 $d = \DateTime
::createFromFormat('Y-m-d', $expecteds['ddn_adh']);
457 $expected_str = ' (82 years old)';
458 $this->string($adh->getAge())->isIdenticalTo($expected_str);
459 $this->boolean($adh->hasChildren())->isFalse();
460 $this->boolean($adh->hasParent())->isFalse();
461 $this->boolean($adh->hasPicture())->isFalse();
463 $this->string($adh->sadmin
)->isIdenticalTo('No');
464 $this->string($adh->sdue_free
)->isIdenticalTo('No');
465 $this->string($adh->sappears_in_list
)->isIdenticalTo('Yes');
466 $this->string($adh->sstaff
)->isIdenticalTo('No');
467 $this->string($adh->sactive
)->isIdenticalTo('Active');
468 $this->variable($adh->stitle
)->isNull();
469 $this->string($adh->sstatus
)->isIdenticalTo('Non-member');
470 $this->string($adh->sfullname
)->isIdenticalTo('DURAND René');
471 $this->string($adh->saddress
)->isIdenticalTo('66, boulevard De Oliveira');
472 $this->string($adh->sname
)->isIdenticalTo('DURAND René');
474 $this->string($adh->getAddress())->isIdenticalTo($expecteds['adresse_adh']);
475 $this->string($adh->getAddressContinuation())->isEmpty();
476 $this->string($adh->getZipcode())->isIdenticalTo($expecteds['cp_adh']);
477 $this->string($adh->getTown())->isIdenticalTo($expecteds['ville_adh']);
478 $this->string($adh->getCountry())->isIdenticalTo($expecteds['pays_adh']);
480 $this->string($adh::getSName($this->zdb
, $adh->id
))->isIdenticalTo('DURAND René');
481 $this->string($adh->getRowClass())->isIdenticalTo('active cotis-never');
485 * Check contributions expecteds
487 * @param Contribution $contrib Contribution instance, if any
488 * @param array $new_expecteds Changes on expected values
492 private function checkContribExpected($contrib = null, $new_expecteds = [])
494 if ($contrib === null) {
495 $contrib = $this->contrib
;
498 $date_begin = $contrib->raw_begin_date
;
499 $date_end = clone $date_begin;
500 $date_end->add(new \
DateInterval('P1Y'));
502 $this->object($contrib->raw_date
)->isInstanceOf('DateTime');
503 $this->object($contrib->raw_begin_date
)->isInstanceOf('DateTime');
504 $this->object($contrib->raw_end_date
)->isInstanceOf('DateTime');
507 'id_adh' => "{$this->adh->id}",
508 'id_type_cotis' => 1,
509 'montant_cotis' => '92',
510 'type_paiement_cotis' => '3',
511 'info_cotis' => 'FAKER' . $this->seed
,
512 'date_fin_cotis' => $date_end->format('Y-m-d'),
514 $expecteds = array_merge($expecteds, $new_expecteds);
516 $this->string($contrib->raw_end_date
->format('Y-m-d'))->isIdenticalTo($expecteds['date_fin_cotis']);
518 foreach ($expecteds as $key => $value) {
519 $property = $this->contrib
->fields
[$key]['propname'];
521 case \Galette\Entity\ContributionsTypes
::PK
:
522 $ct = $this->contrib
->type
;
523 if ($ct instanceof \Galette\Entity\ContributionsTypes
) {
524 $this->integer((int)$ct->id
)->isIdenticalTo($value);
526 $this->integer($ct)->isIdenticalTo($value);
530 $this->variable($contrib->$property)->isEqualTo($value, $property);
535 //load member from db
536 $this->adh
= new \Galette\Entity\
Adherent($this->zdb
, $this->adh
->id
);
537 //member is now up-to-date
538 $this->string($this->adh
->getRowClass())->isIdenticalTo('active cotis-ok');
539 $this->string($this->adh
->due_date
)->isIdenticalTo($this->contrib
->end_date
);
540 $this->boolean($this->adh
->isUp2Date())->isTrue();
544 * Test contribution creation
548 public function testCreation()
550 $this->createAdherent();
551 //create contribution for member
552 $this->createContribution();
556 * Test end date retrieving
557 * This is based on some Preferences parameters
561 public function testRetrieveEndDate()
564 $orig_pref_beg_membership = $this->preferences
->pref_beg_membership
;
565 $orig_pref_membership_ext = $this->preferences
->pref_membership_ext
;
566 $orig_pref_membership_offermonths = $this->preferences
->pref_membership_offermonths
;
568 $contrib = new \Galette\Entity\
Contribution(
571 ['type' => 1] //anual fee
574 // First, check for 12 months renewal
575 $expected = new \
DateTime();
576 $expected->add(new \
DateInterval('P1Y'));
577 $this->string($contrib->end_date
)->isIdenticalTo($expected->format('Y-m-d'));
579 //unset pref_beg_membership and pref_membership_ext
580 $preferences->pref_beg_membership
= '';
581 $preferences->pref_membership_ext
= '';
585 $contrib = new \Galette\Entity\
Contribution(
588 ['type' => 1] //anual fee
592 ->isInstanceOf('RuntimeException')
593 ->hasMessage('Unable to define end date; none of pref_beg_membership nor pref_membership_ext are defined!');
595 // Second, test with beginning of membership date
596 $preferences->pref_beg_membership
= '29/05';
597 $expected = new \
DateTime();
598 $expected->setDate(date('Y'), 5, 29);
599 if ($expected < new \
DateTime()) {
600 $expected->add(new \
DateInterval('P1Y'));
603 $contrib = new \Galette\Entity\
Contribution(
606 ['type' => 1] // anual fee
608 $this->string($contrib->end_date
)->isIdenticalTo($expected->format('Y-m-d'));
610 // Third, test with beginning of membership date and i2 last months offered
611 $beginning = new \
DateTime();
612 $beginning->add(new \
DateInterval('P1M'));
613 $preferences->pref_beg_membership
= $beginning->format('t/m'); // end of next month
614 $preferences->pref_membership_offermonths
= 2;
615 $expected = clone $beginning;
616 $expected->add(new \
DateInterval('P1Y'));
618 $contrib = new \Galette\Entity\
Contribution(
621 ['type' => 1] // anual fee
623 $this->string($contrib->end_date
)->isIdenticalTo($expected->format('Y-m-t'));
626 $preferences->pref_beg_membership
= $orig_pref_beg_membership;
627 $preferences->pref_membership_ext
= $orig_pref_membership_ext;
628 $preferences->pref_membership_offermonths
= $orig_pref_membership_offermonths;
632 * Test checkOverlap method
636 public function testCheckOverlap()
638 $adh = new \Galette\Entity\
Adherent($this->zdb
);
639 $adh->setDependencies(
641 $this->members_fields
,
645 $check = $adh->check(
647 'nom_adh' => 'Overlapped',
648 'date_crea_adh' => date(_T("Y-m-d")),
649 \Galette\Entity\Status
::PK
=> \Galette\Entity\Status
::DEFAULT_STATUS
,
650 'fingerprint' => 'FAKER' . $this->seed
655 if (is_array($check)) {
658 $this->boolean($check)->isTrue();
660 $store = $adh->store();
661 $this->boolean($store)->isTrue();
663 //create first contribution for member
664 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
666 $now = new \
DateTime();
667 $end_date = clone $now;
668 $end_date->add(new \
DateInterval('P1Y'));
670 \Galette\Entity\Adherent
::PK
=> $adh->id
,
671 \Galette\Entity\ContributionsTypes
::PK
=> 1, //anual fee
672 'montant_cotis' => 20,
673 'type_paiement_cotis' => \Galette\Entity\PaymentType
::CHECK
,
674 'date_enreg' => $now->format(_T("Y-m-d")),
675 'date_debut_cotis' => $now->format(_T("Y-m-d")),
676 'date_fin_cotis' => $end_date->format(_T("Y-m-d")),
677 'info_cotis' => 'FAKER' . $this->seed
680 $check = $contrib->check($data, [], []);
681 if (is_array($check)) {
684 $this->boolean($check)->isTrue();
685 $this->boolean($contrib->checkOverlap())->isTrue();
687 $store = $contrib->store();
688 $this->boolean($store)->isTrue();
690 //load member from db
691 $adh = new \Galette\Entity\
Adherent($this->zdb
, $adh->id
);
693 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
694 $begin = clone $end_date;
695 $begin->sub(new \
DateInterval('P3M'));
696 $end_date = clone $begin;
697 $end_date->add(new \
DateInterval('P1Y'));
699 \Galette\Entity\Adherent
::PK
=> $adh->id
,
700 \Galette\Entity\ContributionsTypes
::PK
=> 1, //anual fee
701 'montant_cotis' => 20,
702 'type_paiement_cotis' => \Galette\Entity\PaymentType
::CHECK
,
703 'date_enreg' => $now->format(_T("Y-m-d")),
704 'date_debut_cotis' => $begin->format(_T("Y-m-d")),
705 'date_fin_cotis' => $end_date->format(_T("Y-m-d")),
706 'info_cotis' => 'FAKER' . $this->seed
709 $check = $contrib->check($data, [], []);
710 $this->array($check)->isIdenticalTo([
711 '- Membership period overlaps period starting at ' . $now->format('Y-m-d')
715 function () use ($contrib) {
716 $store = $contrib->store();
719 ->isInstanceOf('RuntimeException')
720 ->message
->startWith('Existing errors prevents storing contribution');
724 * Test checkOverlap method that throws an exception
728 public function testCheckOverlapWException()
730 $zdb = new \mock\Galette\Core\
Db();
731 $this->calling($zdb)->execute
= function ($o) {
732 if ($o instanceof \Zend\Db\Sql\Select
) {
733 throw new \
LogicException('Error executing query!', 123);
737 $contrib = new \Galette\Entity\
Contribution($zdb, $this->login
);
738 $this->boolean($contrib->checkOverlap())->isFalse();
747 public function testGetFieldLabel()
749 $this->string($this->contrib
->getFieldLabel('montant_cotis'))
750 ->isIdenticalTo('Amount');
752 $this->string($this->contrib
->getFieldLabel('date_debut_cotis'))
753 ->isIdenticalTo('Date of contribution');
755 $this->contrib
->type
= 1;
756 $this->string($this->contrib
->getFieldLabel('date_debut_cotis'))
757 ->isIdenticalTo('Start date of membership');
761 * Test contribution loading
765 public function testLoad()
767 $this->login
= new \mock\Galette\Core\
Login($this->zdb
, $this->i18n
, $this->session
);
768 $this->calling($this->login
)->isLogged
= true;
769 $this->calling($this->login
)->isStaff
= true;
770 $this->calling($this->login
)->isAdmin
= true;
772 $this->createAdherent();
774 //create contribution for member
775 $this->createContribution();
777 $id = $this->contrib
->id
;
778 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
780 $this->boolean($contrib->load((int)$id))->isTrue();
781 $this->checkContribExpected($contrib);
783 $this->boolean($contrib->load(1355522012))->isFalse();
787 * Test contribution removal
791 public function testRemove()
793 $this->createAdherent();
794 $this->createContribution();
796 $id = (int)$this->contrib
->id
;
797 $this->boolean($this->contrib
->remove())->isTrue();
799 $contrib = new \Galette\Entity\
Contribution($this->zdb
, $this->login
);
800 $this->boolean($this->contrib
->remove())->isFalse();