4 * Copyright © 2003-2024 The Galette Team
6 * This file is part of Galette (https://galette.eu).
8 * Galette is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * Galette is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
22 namespace Galette\Repository
;
25 use Laminas\Db\ResultSet\ResultSet
;
28 use Laminas\Db\Sql\Expression
;
30 use Galette\Core\Login
;
31 use Galette\Core\History
;
32 use Galette\Entity\Contribution
;
33 use Galette\Entity\Adherent
;
34 use Galette\Entity\Transaction
;
35 use Galette\Entity\ContributionsTypes
;
36 use Galette\Filters\ContributionsList
;
37 use Laminas\Db\Sql\Select
;
40 * Contributions class for galette
42 * @author Johan Cwiklinski <johan@x-tnd.be>
46 public const TABLE
= Contribution
::TABLE
;
47 public const PK
= Contribution
::PK
;
49 private ContributionsList
$filters;
50 private int $count = 0;
54 private float $sum = 0;
55 /** @var array<int> */
56 private array $current_selection;
61 * @param Db $zdb Database
62 * @param Login $login Login
63 * @param ?ContributionsList $filters Filtering
65 public function __construct(Db
$zdb, Login
$login, ?ContributionsList
$filters = null)
68 $this->login
= $login;
70 if ($filters === null) {
71 $this->filters
= new ContributionsList();
73 $this->filters
= $filters;
78 * Get contributions list for a specific transaction
80 * @param int $trans_id Transaction identifier
82 * @return Contribution[]
84 public function getListFromTransaction(int $trans_id): array
86 $this->filters
->from_transaction
= $trans_id;
87 return $this->getList(true);
91 * Get contributions list for a specific transaction
93 * @param array<int> $ids an array of members id that has been selected
94 * @param bool $as_contrib return the results as an array of
95 * @param ?array<string> $fields field(s) name(s) to get. Should be a string or
96 * an array. If null, all fields will be returned
98 * @return array<int, Contribution>|false
100 public function getArrayList(array $ids, bool $as_contrib = false, ?
array $fields = null): array|
false
102 if (count($ids) < 1) {
103 Analog
::log('No contribution selected.', Analog
::INFO
);
107 $this->current_selection
= $ids;
108 $list = $this->getList($as_contrib, $fields);
110 foreach ($list as $entry) {
111 $array_list[] = $entry;
117 * Get contributions list
119 * @param bool $as_contrib return the results as an array of
120 * Contribution object.
121 * @param ?array<string> $fields field(s) name(s) to get. Should be a string or
122 * an array. If null, all fields will be returned
124 * @return array<int, Contribution>|ResultSet
126 public function getList(bool $as_contrib = false, ?
array $fields = null): array|ResultSet
129 $select = $this->buildSelect($fields);
131 $this->filters
->setLimits($select);
133 $contributions = array();
134 $results = $this->zdb
->execute($select);
136 foreach ($results as $row) {
137 $contributions[] = new Contribution($this->zdb
, $this->login
, $row);
140 $contributions = $results;
142 return $contributions;
143 } catch (Throwable
$e) {
145 'Cannot list contributions | ' . $e->getMessage(),
153 * Builds the SELECT statement
155 * @param ?array<string> $fields fields list to retrieve
157 * @return Select SELECT statement
159 private function buildSelect(?
array $fields): Select
163 if (is_array($fields) && count($fields)) {
164 $fieldsList = $fields;
167 $select = $this->zdb
->select(self
::TABLE
, 'a');
168 $select->columns($fieldsList);
171 array('p' => PREFIX_DB
. Adherent
::TABLE
),
172 'a.' . Adherent
::PK
. '= p.' . Adherent
::PK
,
176 $this->buildWhereClause($select);
177 $select->order(self
::buildOrderClause());
179 $this->calculateSum($select);
181 $this->proceedCount($select);
184 } catch (Throwable
$e) {
186 'Cannot build SELECT clause for contributions | ' . $e->getMessage(),
194 * Count contributions from the query
196 * @param Select $select Original select
200 private function proceedCount(Select
$select): void
203 $countSelect = clone $select;
204 $countSelect->reset($countSelect::COLUMNS
);
205 $countSelect->reset($countSelect::JOINS
);
206 $countSelect->reset($countSelect::ORDER
);
207 $countSelect->columns(
209 self
::PK
=> new Expression('COUNT(' . self
::PK
. ')')
213 $results = $this->zdb
->execute($countSelect);
214 $result = $results->current();
217 $this->count
= $result->$k;
218 $this->filters
->setCounter($this->count
);
219 } catch (Throwable
$e) {
221 'Cannot count contributions | ' . $e->getMessage(),
229 * Calculate sum of all selected contributions
231 * @param Select $select Original select
235 private function calculateSum(Select
$select): void
238 $sumSelect = clone $select;
239 $sumSelect->reset($sumSelect::COLUMNS
);
240 $sumSelect->reset($sumSelect::JOINS
);
241 $sumSelect->reset($sumSelect::ORDER
);
244 'contribsum' => new Expression('SUM(montant_cotis)')
248 $results = $this->zdb
->execute($sumSelect);
249 $result = $results->current();
250 if ($result->contribsum
) {
251 $this->sum
= round($result->contribsum
, 2);
253 } catch (Throwable
$e) {
255 'Cannot calculate contributions sum | ' . $e->getMessage(),
263 * Builds the order clause
265 * @return array<string> SQL ORDER clauses
267 private function buildOrderClause(): array
271 switch ($this->filters
->orderby
) {
272 case ContributionsList
::ORDERBY_ID
:
273 $order[] = Contribution
::PK
. ' ' . $this->filters
->ordered
;
275 case ContributionsList
::ORDERBY_DATE
:
276 $order[] = 'date_enreg ' . $this->filters
->ordered
;
278 case ContributionsList
::ORDERBY_BEGIN_DATE
:
279 $order[] = 'date_debut_cotis ' . $this->filters
->ordered
;
281 case ContributionsList
::ORDERBY_END_DATE
:
282 $order[] = 'date_fin_cotis ' . $this->filters
->ordered
;
284 case ContributionsList
::ORDERBY_MEMBER
:
285 $order[] = 'nom_adh ' . $this->filters
->ordered
;
286 $order[] = 'prenom_adh ' . $this->filters
->ordered
;
288 case ContributionsList
::ORDERBY_TYPE
:
289 $order[] = ContributionsTypes
::PK
;
291 case ContributionsList
::ORDERBY_AMOUNT
:
292 $order[] = 'montant_cotis ' . $this->filters
->ordered
;
295 Hum... I really do not know how to sort a query with a value that
296 is calculated code side :/
297 case ContributionsList::ORDERBY_DURATION:
299 case ContributionsList
::ORDERBY_PAYMENT_TYPE
:
300 $order[] = 'type_paiement_cotis ' . $this->filters
->ordered
;
303 $order[] = $this->filters
->orderby
. ' ' . $this->filters
->ordered
;
311 * Builds where clause, for filtering on simple list mode
313 * @param Select $select Original select
317 private function buildWhereClause(Select
$select): void
319 $field = 'date_debut_cotis';
321 switch ($this->filters
->date_field
) {
322 case ContributionsList
::DATE_RECORD
:
323 $field = 'date_enreg';
325 case ContributionsList
::DATE_END
:
326 $field = 'date_fin_cotis';
328 case ContributionsList
::DATE_BEGIN
:
330 $field = 'date_debut_cotis';
334 if (isset($this->current_selection
)) {
335 $select->where
->in('a.' . self
::PK
, $this->current_selection
);
339 if ($this->filters
->start_date_filter
!= null) {
340 $d = new \
DateTime($this->filters
->rstart_date_filter
);
341 $select->where
->greaterThanOrEqualTo(
347 if ($this->filters
->end_date_filter
!= null) {
348 $d = new \
DateTime($this->filters
->rend_date_filter
);
349 $select->where
->lessThanOrEqualTo(
355 if ($this->filters
->payment_type_filter
!== null) {
356 $select->where
->equalTo(
357 'type_paiement_cotis',
358 $this->filters
->payment_type_filter
362 if ($this->filters
->from_transaction
!== false) {
363 $select->where
->equalTo(
365 $this->filters
->from_transaction
369 if ($this->filters
->max_amount
!== null) {
371 '(montant_cotis <= ' . $this->filters
->max_amount
.
372 ' OR montant_cotis IS NULL)'
376 $member_clause = null;
377 if ($this->filters
->filtre_cotis_adh
!= null) {
378 $member_clause = [$this->filters
->filtre_cotis_adh
];
379 if (!$this->login
->isAdmin() && !$this->login
->isStaff() && $this->filters
->filtre_cotis_adh
!= $this->login
->id
) {
380 $member = new Adherent(
382 (int)$this->filters
->filtre_cotis_adh
,
391 !$member->hasParent() ||
392 $member->parent
->id
!= $this->login
->id
395 'Trying to display contributions for member #' . $member->id
.
396 ' without appropriate ACLs',
399 $this->filters
->filtre_cotis_adh
= $this->login
->id
;
400 $member_clause = [$this->login
->id
];
403 } elseif ($this->filters
->filtre_cotis_children
!== false) {
404 $member_clause = [$this->login
->id
];
405 $member = new Adherent(
407 (int)$this->filters
->filtre_cotis_children
,
415 foreach ($member->children
as $child) {
416 $member_clause[] = $child->id
;
418 } elseif (!$this->login
->isAdmin() && !$this->login
->isStaff()) {
419 //non staff members can only view their own contributions
420 $member_clause = $this->login
->id
;
423 if ($member_clause !== null) {
426 'a.' . Adherent
::PK
=> $member_clause
431 if ($this->filters
->filtre_transactions
=== true) {
432 $select->where('a.trans_id IS NULL');
434 } catch (Throwable
$e) {
436 __METHOD__
. ' | ' . $e->getMessage(),
444 * Get count for current query
448 public function getCount(): int
458 public function getSum(): float
464 * Remove specified contributions
466 * @param integer|array<int> $ids Contributions identifiers to delete
467 * @param History $hist History
468 * @param boolean $transaction True to begin a database transaction
472 public function remove(int|
array $ids, History
$hist, bool $transaction = true): bool
475 if (is_array($ids)) {
477 } elseif (is_numeric($ids)) {
480 //not numeric and not an array: incorrect.
482 'Asking to remove contribution, but without providing an array or a single numeric value.',
490 $this->zdb
->connection
->beginTransaction();
492 $select = $this->zdb
->select(self
::TABLE
);
493 $select->where
->in(self
::PK
, $list);
494 $contributions = $this->zdb
->execute($select);
495 foreach ($contributions as $contribution) {
496 $c = new Contribution($this->zdb
, $this->login
, $contribution);
497 $res = $c->remove(false);
498 if ($res === false) {
499 throw new \
Exception();
503 $this->zdb
->connection
->commit();
508 print_r($list, true),
509 _T("Contributions deleted (%list)")
513 } catch (Throwable
$e) {
515 $this->zdb
->connection
->rollBack();
518 'An error occurred trying to remove contributions | ' .