]> git.agnieray.net Git - galette.git/blob - tests/Galette/Entity/tests/units/Contribution.php
f668cab9f0bf6062c95ef4d364553ae22bbec906
[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 testeach 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 $delete = $this->zdb->delete(\Galette\Entity\Adherent::TABLE);
72 $delete->where(['fingerprint' => 'FAKER' . $this->seed]);
73 $this->zdb->execute($delete);
74 }
75
76 /**
77 * Set up tests
78 *
79 * @param string $testMethod Calling method
80 *
81 * @return void
82 */
83 public function beforeTestMethod($testMethod)
84 {
85 parent::beforeTestMethod($testMethod);
86 $this->initContributionsTypes();
87
88 $this->contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
89
90 $this->adh = new \Galette\Entity\Adherent($this->zdb);
91 $this->adh->setDependencies(
92 $this->preferences,
93 $this->members_fields,
94 $this->history
95 );
96 }
97
98 /**
99 * Create test contribution in database
100 *
101 * @return void
102 */
103 private function createContribution()
104 {
105 $bdate = new \DateTime(); // 2020-11-07
106 $bdate->sub(new \DateInterval('P5M')); // 2020-06-07
107 $bdate->add(new \DateInterval('P3D')); // 2020-06-10
108
109 $edate = clone $bdate;
110 $edate->add(new \DateInterval('P1Y'));
111
112 $data = [
113 'id_adh' => $this->adh->id,
114 'id_type_cotis' => 1,
115 'montant_cotis' => 92,
116 'type_paiement_cotis' => 3,
117 'info_cotis' => 'FAKER' . $this->seed,
118 'date_enreg' => $bdate->format('Y-m-d'),
119 'date_debut_cotis' => $bdate->format('Y-m-d'),
120 'date_fin_cotis' => $edate->format('Y-m-d'),
121 ];
122 $this->createContrib($data);
123 $this->checkContribExpected();
124 }
125
126 /**
127 * Loads contribution from a resultset
128 *
129 * @param ResultSet $rs ResultSet
130 *
131 * @return void
132 */
133 private function loadContribution($rs)
134 {
135 $this->adh = new \Galette\Entity\Contribution($this->zdb, $this->login, $rs);
136 }
137
138 /**
139 * Test empty contribution
140 *
141 * @return void
142 */
143 public function testEmpty()
144 {
145 $contrib = $this->contrib;
146 $this->variable($contrib->id)->isNull();
147 $this->variable($contrib->isCotis())->isNull();
148 $this->variable($contrib->is_cotis)->isNull();
149 $this->variable($contrib->date)->isNull();
150 $this->variable($contrib->begin_date)->isNull();
151 $this->variable($contrib->end_date)->isNull();
152 $this->variable($contrib->raw_date)->isNull();
153 $this->variable($contrib->raw_begin_date)->isNull();
154 $this->variable($contrib->raw_end_date)->isNull();
155 $this->string($contrib->duration)->isEmpty();
156 $this->variable($contrib->payment_type)->isNull();
157 $this->string($contrib->spayment_type)->isIdenticalTo('-');
158 $this->variable($contrib->model)->isNull();
159 $this->variable($contrib->member)->isNull();
160 $this->variable($contrib->type)->isNull();
161 $this->variable($contrib->amount)->isNull();
162 $this->variable($contrib->orig_amount)->isNull();
163 $this->variable($contrib->info)->isNull();
164 $this->variable($contrib->transaction)->isNull();
165 $this->array($contrib->fields)
166 ->hasSize(11)
167 ->hasKeys([
168 \Galette\Entity\Contribution::PK,
169 \Galette\Entity\Adherent::PK,
170 \Galette\Entity\ContributionsTypes::PK,
171 'montant_cotis',
172 'type_paiement_cotis',
173 'info_cotis',
174 'date_debut_cotis'
175 ]);
176
177 $this->string($contrib->getRowClass())->isIdenticalTo('cotis-give');
178 $this->variable($contrib::getDueDate($this->zdb, 1))->isNull();
179 $this->boolean($contrib->isTransactionPart())->isFalse();
180 $this->boolean($contrib->isTransactionPartOf(1))->isFalse();
181 $this->string($contrib->getRawType())->isIdenticalTo('donation');
182 $this->string($contrib->getTypeLabel())->isIdenticalTo('Donation');
183 $this->string($contrib->getPaymentType())->isIdenticalTo('-');
184 $this->variable($contrib->unknown_property)->isNull();
185 }
186
187 /**
188 * Test getter and setter special cases
189 *
190 * @return void
191 */
192 public function testGetterSetter()
193 {
194 $contrib = $this->contrib;
195
196 //set a bad date
197 $contrib->begin_date = 'not a date';
198 $this->variable($contrib->raw_begin_date)->isNull();
199 $this->variable($contrib->begin_date)->isNull();
200
201 $contrib->begin_date = '2017-06-17';
202 $this->object($contrib->raw_begin_date)->isInstanceOf('DateTime');
203 $this->string($contrib->begin_date)->isIdenticalTo('2017-06-17');
204
205 $contrib->amount = 'not an amount';
206 $this->variable($contrib->amount)->isNull();
207 $contrib->amount = 0;
208 $this->variable($contrib->amount)->isNull();
209 $contrib->amount = 42;
210 $this->integer($contrib->amount)->isIdenticalTo(42);
211 $contrib->amount = '42';
212 $this->string($contrib->amount)->isIdenticalTo('42');
213
214 $contrib->type = 'not a type';
215 $this->variable($contrib->type)->isNull();
216 $contrib->type = 156;
217 $this->object($contrib->type)->isInstanceOf('\Galette\Entity\ContributionsTypes');
218 $this->boolean($contrib->type->id)->isFalse();
219 $contrib->type = 1;
220 $this->object($contrib->type)->isInstanceOf('\Galette\Entity\ContributionsTypes');
221 $this->variable($contrib->type->id)->isEqualTo(1);
222
223 $contrib->transaction = 'not a transaction id';
224 $this->variable($contrib->transaction)->isNull();
225 $contrib->transaction = 46;
226 $this->object($contrib->transaction)->isInstanceOf('\Galette\Entity\Transaction');
227 $this->boolean($contrib->transaction->id)->isFalse();
228
229 $contrib->member = 'not a member';
230 $this->variable($contrib->member)->isNull();
231 $contrib->member = 118218;
232 $this->integer($contrib->member)->isIdenticalTo(118218);
233
234 $contrib->not_a_property = 'abcde';
235 $this->boolean(property_exists($contrib, 'not_a_property'))->isFalse();
236
237 $contrib->payment_type = \Galette\Entity\PaymentType::CASH;
238 $this->string($contrib->getPaymentType())->isIdenticalTo('Cash');
239 $this->string($contrib->spayment_type)->isIdenticalTo('Cash');
240
241 $contrib->payment_type = \Galette\Entity\PaymentType::CHECK;
242 $this->string($contrib->getPaymentType())->isIdenticalTo('Check');
243 $this->string($contrib->spayment_type)->isIdenticalTo('Check');
244
245 $contrib->payment_type = \Galette\Entity\PaymentType::OTHER;
246 $this->string($contrib->getPaymentType())->isIdenticalTo('Other');
247 $this->string($contrib->spayment_type)->isIdenticalTo('Other');
248
249 $contrib->payment_type = \Galette\Entity\PaymentType::CREDITCARD;
250 $this->string($contrib->getPaymentType())->isIdenticalTo('Credit card');
251 $this->string($contrib->spayment_type)->isIdenticalTo('Credit card');
252
253 $contrib->payment_type = \Galette\Entity\PaymentType::TRANSFER;
254 $this->string($contrib->getPaymentType())->isIdenticalTo('Transfer');
255 $this->string($contrib->spayment_type)->isIdenticalTo('Transfer');
256
257 $contrib->payment_type = \Galette\Entity\PaymentType::PAYPAL;
258 $this->string($contrib->getPaymentType())->isIdenticalTo('Paypal');
259 $this->string($contrib->spayment_type)->isIdenticalTo('Paypal');
260 }
261
262 /**
263 * Check contributions expecteds
264 *
265 * @param Contribution $contrib Contribution instance, if any
266 * @param array $new_expecteds Changes on expected values
267 *
268 * @return void
269 */
270 private function checkContribExpected($contrib = null, $new_expecteds = [])
271 {
272 if ($contrib === null) {
273 $contrib = $this->contrib;
274 }
275
276 $date_begin = $contrib->raw_begin_date;
277 $date_end = clone $date_begin;
278 $date_end->add(new \DateInterval('P1Y'));
279
280 $this->object($contrib->raw_date)->isInstanceOf('DateTime');
281 $this->object($contrib->raw_begin_date)->isInstanceOf('DateTime');
282 $this->object($contrib->raw_end_date)->isInstanceOf('DateTime');
283
284 $expecteds = [
285 'id_adh' => "{$this->adh->id}",
286 'id_type_cotis' => 1,
287 'montant_cotis' => '92',
288 'type_paiement_cotis' => '3',
289 'info_cotis' => 'FAKER' . $this->seed,
290 'date_fin_cotis' => $date_end->format('Y-m-d'),
291 ];
292 $expecteds = array_merge($expecteds, $new_expecteds);
293
294 $this->string($contrib->raw_end_date->format('Y-m-d'))->isIdenticalTo($expecteds['date_fin_cotis']);
295
296 foreach ($expecteds as $key => $value) {
297 $property = $this->contrib->fields[$key]['propname'];
298 switch ($key) {
299 case \Galette\Entity\ContributionsTypes::PK:
300 $ct = $this->contrib->type;
301 if ($ct instanceof \Galette\Entity\ContributionsTypes) {
302 $this->integer((int)$ct->id)->isIdenticalTo($value);
303 } else {
304 $this->integer($ct)->isIdenticalTo($value);
305 }
306 break;
307 default:
308 $this->variable($contrib->$property)->isEqualTo($value, $property);
309 break;
310 }
311 }
312
313 //load member from db
314 $this->adh = new \Galette\Entity\Adherent($this->zdb, $this->adh->id);
315 //member is now up-to-date
316 $this->string($this->adh->getRowClass())->isIdenticalTo('active cotis-ok');
317 $this->string($this->adh->due_date)->isIdenticalTo($this->contrib->end_date);
318 $this->boolean($this->adh->isUp2Date())->isTrue();
319 }
320
321 /**
322 * Test contribution creation
323 *
324 * @return void
325 */
326 public function testCreation()
327 {
328 $this->getMemberOne();
329 //create contribution for member
330 $this->createContribution();
331 }
332
333 /**
334 * Test end date retrieving
335 * This is based on some Preferences parameters
336 *
337 * @return void
338 */
339 public function testRetrieveEndDate()
340 {
341 global $preferences;
342 $orig_pref_beg_membership = $this->preferences->pref_beg_membership;
343 $orig_pref_membership_ext = $this->preferences->pref_membership_ext;
344 $orig_pref_membership_offermonths = $this->preferences->pref_membership_offermonths;
345
346 $contrib = new \Galette\Entity\Contribution(
347 $this->zdb,
348 $this->login,
349 ['type' => 1] //anual fee
350 );
351
352 // First, check for 12 months renewal
353 $expected = new \DateTime();
354 $expected->add(new \DateInterval('P1Y'));
355 $this->string($contrib->end_date)->isIdenticalTo($expected->format('Y-m-d'));
356
357 //unset pref_beg_membership and pref_membership_ext
358 $preferences->pref_beg_membership = '';
359 $preferences->pref_membership_ext = '';
360
361 $this->exception(
362 function () {
363 $contrib = new \Galette\Entity\Contribution(
364 $this->zdb,
365 $this->login,
366 ['type' => 1] //anual fee
367 );
368 }
369 )
370 ->isInstanceOf('RuntimeException')
371 ->hasMessage('Unable to define end date; none of pref_beg_membership nor pref_membership_ext are defined!');
372
373 // Second, test with beginning of membership date
374 $preferences->pref_beg_membership = '29/05';
375 $expected = new \DateTime();
376 $expected->setDate(date('Y'), 5, 29);
377 if ($expected < new \DateTime()) {
378 $expected->add(new \DateInterval('P1Y'));
379 }
380
381 $contrib = new \Galette\Entity\Contribution(
382 $this->zdb,
383 $this->login,
384 ['type' => 1] // anual fee
385 );
386 $this->string($contrib->end_date)->isIdenticalTo($expected->format('Y-m-d'));
387
388 // Third, test with beginning of membership date and i2 last months offered
389 $beginning = new \DateTime();
390 $beginning->add(new \DateInterval('P1M'));
391 $preferences->pref_beg_membership = $beginning->format('t/m'); // end of next month
392 $preferences->pref_membership_offermonths = 2;
393 $expected = clone $beginning;
394 $expected->add(new \DateInterval('P1Y'));
395
396 $contrib = new \Galette\Entity\Contribution(
397 $this->zdb,
398 $this->login,
399 ['type' => 1] // anual fee
400 );
401 $this->string($contrib->end_date)->isIdenticalTo($expected->format('Y-m-t'));
402
403 //reset
404 $preferences->pref_beg_membership = $orig_pref_beg_membership;
405 $preferences->pref_membership_ext = $orig_pref_membership_ext;
406 $preferences->pref_membership_offermonths = $orig_pref_membership_offermonths;
407 }
408
409 /**
410 * Test checkOverlap method
411 *
412 * @return void
413 */
414 public function testCheckOverlap()
415 {
416 $adh = new \Galette\Entity\Adherent($this->zdb);
417 $adh->setDependencies(
418 $this->preferences,
419 $this->members_fields,
420 $this->history
421 );
422
423 $check = $adh->check(
424 [
425 'nom_adh' => 'Overlapped',
426 'date_crea_adh' => date(_T("Y-m-d")),
427 \Galette\Entity\Status::PK => \Galette\Entity\Status::DEFAULT_STATUS,
428 'fingerprint' => 'FAKER' . $this->seed
429 ],
430 [],
431 []
432 );
433 if (is_array($check)) {
434 var_dump($check);
435 }
436 $this->boolean($check)->isTrue();
437
438 $store = $adh->store();
439 $this->boolean($store)->isTrue();
440
441 //create first contribution for member
442 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
443
444 $now = new \DateTime();
445 $end_date = clone $now;
446 $end_date->add(new \DateInterval('P1Y'));
447 $data = [
448 \Galette\Entity\Adherent::PK => $adh->id,
449 \Galette\Entity\ContributionsTypes::PK => 1, //anual fee
450 'montant_cotis' => 20,
451 'type_paiement_cotis' => \Galette\Entity\PaymentType::CHECK,
452 'date_enreg' => $now->format(_T("Y-m-d")),
453 'date_debut_cotis' => $now->format(_T("Y-m-d")),
454 'date_fin_cotis' => $end_date->format(_T("Y-m-d")),
455 'info_cotis' => 'FAKER' . $this->seed
456 ];
457
458 $check = $contrib->check($data, [], []);
459 if (is_array($check)) {
460 var_dump($check);
461 }
462 $this->boolean($check)->isTrue();
463 $this->boolean($contrib->checkOverlap())->isTrue();
464
465 $store = $contrib->store();
466 $this->boolean($store)->isTrue();
467
468 //load member from db
469 $adh = new \Galette\Entity\Adherent($this->zdb, $adh->id);
470
471 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
472 $begin = clone $end_date;
473 $begin->sub(new \DateInterval('P3M'));
474 $end_date = clone $begin;
475 $end_date->add(new \DateInterval('P1Y'));
476 $data = [
477 \Galette\Entity\Adherent::PK => $adh->id,
478 \Galette\Entity\ContributionsTypes::PK => 1, //anual fee
479 'montant_cotis' => 20,
480 'type_paiement_cotis' => \Galette\Entity\PaymentType::CHECK,
481 'date_enreg' => $now->format(_T("Y-m-d")),
482 'date_debut_cotis' => $begin->format(_T("Y-m-d")),
483 'date_fin_cotis' => $end_date->format(_T("Y-m-d")),
484 'info_cotis' => 'FAKER' . $this->seed
485 ];
486
487 $check = $contrib->check($data, [], []);
488 $this->array($check)->isIdenticalTo([
489 '- Membership period overlaps period starting at ' . $now->format('Y-m-d')
490 ]);
491
492 $this->exception(
493 function () use ($contrib) {
494 $store = $contrib->store();
495 }
496 )
497 ->isInstanceOf('RuntimeException')
498 ->message->startWith('Existing errors prevents storing contribution');
499 }
500
501 /**
502 * Test checkOverlap method that throws an exception
503 *
504 * @return void
505 */
506 public function testCheckOverlapWException()
507 {
508 $zdb = new \mock\Galette\Core\Db();
509 $this->calling($zdb)->execute = function ($o) {
510 if ($o instanceof \Zend\Db\Sql\Select) {
511 throw new \LogicException('Error executing query!', 123);
512 }
513 };
514
515 $contrib = new \Galette\Entity\Contribution($zdb, $this->login);
516 $this->boolean($contrib->checkOverlap())->isFalse();
517 }
518
519
520 /**
521 * Test fields labels
522 *
523 * @return void
524 */
525 public function testGetFieldLabel()
526 {
527 $this->string($this->contrib->getFieldLabel('montant_cotis'))
528 ->isIdenticalTo('Amount');
529
530 $this->string($this->contrib->getFieldLabel('date_debut_cotis'))
531 ->isIdenticalTo('Date of contribution');
532
533 $this->contrib->type = 1;
534 $this->string($this->contrib->getFieldLabel('date_debut_cotis'))
535 ->isIdenticalTo('Start date of membership');
536 }
537
538 /**
539 * Test contribution loading
540 *
541 * @return void
542 */
543 public function testLoad()
544 {
545 $this->login = new \mock\Galette\Core\Login($this->zdb, $this->i18n);
546 $this->calling($this->login)->isLogged = true;
547 $this->calling($this->login)->isStaff = true;
548 $this->calling($this->login)->isAdmin = true;
549
550 $this->getMemberOne();
551
552 //create contribution for member
553 $this->createContribution();
554
555 $id = $this->contrib->id;
556 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
557
558 $this->boolean($contrib->load((int)$id))->isTrue();
559 $this->checkContribExpected($contrib);
560
561 $this->boolean($contrib->load(1355522012))->isFalse();
562 }
563
564 /**
565 * Test contribution removal
566 *
567 * @return void
568 */
569 public function testRemove()
570 {
571 $this->getMemberOne();
572 $this->createContribution();
573
574 $id = (int)$this->contrib->id;
575 $this->boolean($this->contrib->remove())->isTrue();
576
577 $contrib = new \Galette\Entity\Contribution($this->zdb, $this->login);
578 $this->boolean($this->contrib->remove())->isFalse();
579 }
580 }