/**
* Contribution class for galette
+ * Manage membership fees and donations.
*
* PHP version 5
*
- * Copyright © 2010-2014 The Galette Team
+ * Copyright © 2010-2023 The Galette Team
*
* This file is part of Galette (http://galette.tuxfamily.org).
*
* @package Galette
*
* @author Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2010-2014 The Galette Team
+ * @copyright 2010-2023 The Galette Team
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
* @link http://galette.tuxfamily.org
* @since Available since 0.7dev - 2010-03-11
namespace Galette\Entity;
+use ArrayObject;
+use DateTime;
+use Galette\Events\GaletteEvent;
+use Galette\Features\HasEvent;
use Throwable;
use Analog\Analog;
use Laminas\Db\Sql\Expression;
use Galette\IO\ExternalScript;
use Galette\IO\PdfContribution;
use Galette\Repository\PaymentTypes;
+use Galette\Features\Dynamics;
/**
* Contribution class for galette
+ * Manage membership fees and donations.
*
* @category Entity
* @name Contribution
* @package Galette
* @author Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2010-2014 The Galette Team
+ * @copyright 2010-2023 The Galette Team
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
* @link http://galette.tuxfamily.org
* @since Available since 0.7dev - 2010-03-11
+ *
+ * @property integer $id
+ * @property string $date
+ * @property DateTime $raw_date
+ * @property integer $member
+ * @property ContributionsTypes|int $type
+ * @property double $amount
+ * @property integer $payment_type
+ * @property double $orig_amount
+ * @property string $info
+ * @property string $begin_date
+ * @property DateTime $raw_begin_date
+ * @property string $end_date
+ * @property DateTime $raw_end_date
+ * @property Transaction|null $transaction
+ * @property integer $extension
+ * @property integer $duration
+ * @property string $spayment_type
+ * @property integer $model
*/
class Contribution
{
- use DynamicsTrait;
+ use Dynamics;
+ use HasEvent;
public const TABLE = 'cotisations';
public const PK = 'id_cotis';
+ public const TYPE_FEE = 'fee';
+ public const TYPE_DONATION = 'donation';
+
private $_id;
private $_date;
private $_member;
//fields list and their translation
private $_fields;
+ /** @var Db */
private $zdb;
+ /** @var Login */
private $login;
-
+ /** @var array */
private $errors;
private $sendmail = false;
/**
* Default constructor
*
- * @param Db $zdb Database
- * @param Login $login Login instance
- * @param null|int|ResultSet $args Either a ResultSet row to load
- * a specific contribution, or an type id
- * to just instanciate object
+ * @param Db $zdb Database
+ * @param Login $login Login instance
+ * @param null|int|array|ArrayObject $args Either a ResultSet row to load
+ * a specific contribution, or a type id
+ * to just instantiate object
*/
public function __construct(Db $zdb, Login $login, $args = null)
{
$this->zdb = $zdb;
$this->login = $login;
+ global $preferences;
+ $this->_payment_type = (int)$preferences->pref_default_paymenttype;
+
+ $this
+ ->withAddEvent()
+ ->withEditEvent()
+ ->withoutDeleteEvent()
+ ->activateEvents();
+
/*
* Fields configuration. Each field is an array and must reflect:
* array(
* (string)label,
- * (string) propname
+ * (string) property name
* )
*
* I'd prefer a static private variable for this...
*/
$this->_fields = array(
'id_cotis' => array(
- 'label' => null, //not a field in the form
+ 'label' => _T('Contribution id'), //not a field in the form
'propname' => 'id'
),
Adherent::PK => array(
'propname' => 'info'
),
'date_enreg' => array(
- 'label' => null, //not a field in the form
+ 'label' => _T('Date'), //not a field in the form
'propname' => 'date'
),
'date_debut_cotis' => array(
'label' => _T("Date of contribution:"),
- 'cotlabel' => _T("Start date of membership:"), //if contribution is a cotisation, label differs
+ 'cotlabel' => _T("Start date of membership:"), //if contribution is a membership fee, label differs
'propname' => 'begin_date'
),
'date_fin_cotis' => array(
'propname' => 'end_date'
),
Transaction::PK => array(
- 'label' => null, //not a field in the form
+ 'label' => _T('Transaction ID'), //not a field in the form
'propname' => 'transaction'
),
//this one is not really a field, but is required in some cases...
- //adding it here make simplier to check required fields
+ //adding it here make more simple to check required fields
'duree_mois_cotis' => array(
'label' => _T("Membership extension:"),
'propname' => 'extension'
$this->_amount = $this->_transaction->getMissingAmount();
}
$this->type = (int)$args['type'];
- //calculate begin date for cotisation
+ //calculate begin date for membership fee
$this->_begin_date = $this->_date;
if ($this->_is_cotis) {
- $curend = self::getDueDate($this->zdb, $this->_member);
- if ($curend != '') {
- $dend = new \DateTime($curend);
- $now = date('Y-m-d');
- $dnow = new \DateTime($now);
- if ($dend < $dnow) {
+ $due_date = self::getDueDate($this->zdb, $this->_member);
+ if ($due_date != '') {
+ $now = new \DateTime();
+ $due_date = new \DateTime($due_date);
+ if ($due_date < $now) {
// Member didn't renew on time
- $this->_begin_date = $now;
+ $this->_begin_date = $now->format('Y-m-d');
} else {
- $this->_begin_date = $curend;
+ // Caution : the next_begin_date is the day after the due_date.
+ $next_begin_date = clone $due_date;
+ $next_begin_date->add(new \DateInterval('P1D'));
+ $this->_begin_date = $next_begin_date->format('Y-m-d');
}
}
$this->retrieveEndDate();
{
global $preferences;
- $bdate = new \DateTime($this->_begin_date);
+ $now = new \DateTime();
+ $begin_date = new \DateTime($this->_begin_date);
if ($preferences->pref_beg_membership != '') {
//case beginning of membership
list($j, $m) = explode('/', $preferences->pref_beg_membership);
- $edate = new \DateTime($bdate->format('Y') . '-' . $m . '-' . $j);
- while ($edate <= $bdate) {
- $edate->modify('+1 year');
+ $next_begin_date = new \DateTime($begin_date->format('Y') . '-' . $m . '-' . $j);
+ while ($next_begin_date <= $begin_date) {
+ $next_begin_date->add(new \DateInterval('P1Y'));
}
if ($preferences->pref_membership_offermonths > 0) {
- //count days until end of membership date
- $diff1 = (int)$bdate->diff($edate)->format('%a');
+ //count days until next membership begin date
+ $diff1 = (int)$now->diff($next_begin_date)->format('%a');
- //count days beetween end of membership date and offered months
- $tdate = clone $edate;
- $tdate->modify('-' . $preferences->pref_membership_offermonths . ' month');
- $diff2 = (int)$edate->diff($tdate)->format('%a');
+ //count days between next membership begin date and offered months
+ $tdate = clone $next_begin_date;
+ $tdate->sub(new \DateInterval('P' . $preferences->pref_membership_offermonths . 'M'));
+ $diff2 = (int)$next_begin_date->diff($tdate)->format('%a');
- //when number of days until end of membership is less than for offered months, it's free :)
+ //when number of days until next membership begin date is less than or equal to the offered months, it's free :)
if ($diff1 <= $diff2) {
- $edate->modify('+1 year');
+ $next_begin_date->add(new \DateInterval('P1Y'));
}
}
- $this->_end_date = $edate->format('Y-m-d');
+ // Caution : the end_date to retrieve is the day before the next_begin_date.
+ $end_date = clone $next_begin_date;
+ $end_date->sub(new \DateInterval('P1D'));
+ $this->_end_date = $end_date->format('Y-m-d');
} elseif ($preferences->pref_membership_ext != '') {
//case membership extension
if ($this->_extension == null) {
$this->_extension = $preferences->pref_membership_ext;
}
$dext = new \DateInterval('P' . $this->_extension . 'M');
- $edate = $bdate->add($dext);
- $this->_end_date = $edate->format('Y-m-d');
+ // Caution : the end_date to retrieve is the day before the next_begin_date.
+ $next_begin_date = $begin_date->add($dext);
+ $end_date = clone $next_begin_date;
+ $end_date->sub(new \DateInterval('P1D'));
+ $this->_end_date = $end_date->format('Y-m-d');
} else {
throw new \RuntimeException(
'Unable to define end date; none of pref_beg_membership nor pref_membership_ext are defined!'
/**
* Loads a contribution from its id
*
- * @param int $id the identifiant for the contribution to load
+ * @param int $id the identifier for the contribution to load
*
* @return bool true if query succeed, false otherwise
*/
public function load($id)
{
+ if (!$this->login->isLogged() && $this->login->id == '') {
+ return false;
+ }
+
try {
- $select = $this->zdb->select(self::TABLE);
- $select->where(self::PK . ' = ' . $id);
+ $select = $this->zdb->select(self::TABLE, 'c');
+ $select->join(
+ array('a' => PREFIX_DB . Adherent::TABLE),
+ 'c.' . Adherent::PK . '=a.' . Adherent::PK,
+ array()
+ );
//restrict query on current member id if he's not admin nor staff member
if (!$this->login->isAdmin() && !$this->login->isStaff()) {
- $select->where(Adherent::PK . ' = ' . $this->login->id);
+ $select->where
+ ->nest()
+ ->equalTo('a.' . Adherent::PK, $this->login->id)
+ ->or
+ ->equalTo('a.parent_id', $this->login->id)
+ ->unnest()
+ ->and
+ ->equalTo('c.' . self::PK, $id)
+ ;
+ } else {
+ $select->where->equalTo(self::PK, $id);
}
$results = $this->zdb->execute($select);
$this->loadFromRS($row);
return true;
} else {
- throw new \Exception(
- 'No contribution #' . $id . ' (user ' . $this->login->id . ')'
+ Analog::log(
+ 'No contribution #' . $id . ' (user ' . $this->login->id . ')',
+ Analog::ERROR
);
+ return false;
}
} catch (Throwable $e) {
Analog::log(
$e->getMessage(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
/**
* Populate object from a resultset row
*
- * @param ResultSet $r the resultset row
+ * @param ArrayObject $r the resultset row
*
* @return void
*/
- private function loadFromRS($r)
+ private function loadFromRS(ArrayObject $r)
{
$pk = self::PK;
$this->_id = (int)$r->$pk;
$this->_date = $r->date_enreg;
- $this->_amount = $r->montant_cotis;
- //save original amount, we need it for transactions parts calulations
- $this->_orig_amount = $r->montant_cotis;
+ $this->_amount = (double)$r->montant_cotis;
+ //save original amount, we need it for transactions parts calculations
+ $this->_orig_amount = (double)$r->montant_cotis;
$this->_payment_type = $r->type_paiement_cotis;
$this->_info = $r->info_cotis;
$this->_begin_date = $r->date_debut_cotis;
- $enddate = $r->date_fin_cotis;
+ $end_date = $r->date_fin_cotis;
//do not work with knows bad dates...
- //the one with BC comes from 0.63/pgsl demo... Why the hell a so
- //strange date? dont know :(
+ //the one with BC comes from 0.63/pgsql demo... Why the hell a so
+ //strange date? don't know :(
if (
- $enddate !== '0000-00-00'
- && $enddate !== '1901-01-01'
- && $enddate !== '0001-01-01 BC'
+ $end_date !== '0000-00-00'
+ && $end_date !== '1901-01-01'
+ && $end_date !== '0001-01-01 BC'
) {
$this->_end_date = $r->date_fin_cotis;
}
$fields = array_keys($this->_fields);
foreach ($fields as $key) {
- //first of all, let's sanitize values
+ //first, let's sanitize values
$key = strtolower($key);
$prop = '_' . $this->_fields[$key]['propname'];
try {
$d = \DateTime::createFromFormat(__("Y-m-d"), $value);
if ($d === false) {
- throw new \Exception('Incorrect format');
+ //try with non localized date
+ $d = \DateTime::createFromFormat("Y-m-d", $value);
+ if ($d === false) {
+ throw new \Exception('Incorrect format');
+ }
}
$this->$prop = $d->format('Y-m-d');
} catch (Throwable $e) {
}
break;
case 'montant_cotis':
- $this->_amount = $value;
$value = strtr($value, ',', '.');
+ if (!empty($value) || $value === '0') {
+ $this->_amount = (double)$value;
+ }
if (!is_numeric($value) && $value !== '') {
$this->errors[] = _T("- The amount must be an integer!");
}
}
}
- if ($this->isCotis() && count($this->errors) == 0) {
+ if ($this->isFee() && count($this->errors) == 0) {
$overlap = $this->checkOverlap();
if ($overlap !== true) {
- if ($overlap === false) {
- $this->errors[] = _T("An error occurred checking overlaping fees :(");
- } else {
- //method directly return error message
- $this->errors[] = $overlap;
- }
+ //method directly return error message
+ $this->errors[] = $overlap;
}
}
if (count($this->errors) > 0) {
Analog::log(
- 'Some errors has been throwed attempting to edit/store a contribution' .
+ 'Some errors has been threw attempting to edit/store a contribution' .
print_r($this->errors, true),
Analog::ERROR
);
{
try {
$select = $this->zdb->select(self::TABLE, 'c');
+ //@phpstan-ignore-next-line
$select->columns(
array('date_debut_cotis', 'date_fin_cotis')
)->join(
array('ct' => PREFIX_DB . ContributionsTypes::TABLE),
'c.' . ContributionsTypes::PK . '=ct.' . ContributionsTypes::PK,
array()
- )->where(Adherent::PK . ' = ' . $this->_member)
+ )->where([Adherent::PK => $this->_member])
->where(array('cotis_extension' => new Expression('true')))
->where->nest->nest
->greaterThanOrEqualTo('date_debut_cotis', $this->_begin_date)
- ->lessThan('date_debut_cotis', $this->_end_date)
+ ->lessThanOrEqualTo('date_debut_cotis', $this->_end_date)
->unnest
->or->nest
- ->greaterThan('date_fin_cotis', $this->_begin_date)
+ ->greaterThanOrEqualTo('date_fin_cotis', $this->_begin_date)
->lessThanOrEqualTo('date_fin_cotis', $this->_end_date);
if ($this->id != '') {
- $select->where(self::PK . ' != ' . $this->id);
+ $select->where->notEqualTo(self::PK, $this->id);
}
$results = $this->zdb->execute($select);
if ($results->count() > 0) {
$result = $results->current();
- $d = new \DateTime($result->date_debut_cotis);
+
+ $d_begin = new \DateTime($result->date_debut_cotis);
+ $d_end = new \DateTime($result->date_fin_cotis);
+
+ if ($d_begin->format('m-d') == $d_end->format('m-d') && $result->date_fin_cotis == $this->_begin_date) {
+ //see https://bugs.galette.eu/issues/1762
+ return true;
+ }
return _T("- Membership period overlaps period starting at ") .
- $d->format(__("Y-m-d"));
+ $d_begin->format(__("Y-m-d"));
}
return true;
} catch (Throwable $e) {
Analog::log(
- 'An error occurred checking overlaping fee. ' . $e->getMessage(),
+ 'An error occurred checking overlapping fee. ' . $e->getMessage(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
}
//no end date, let's take database defaults
- if (!$this->isCotis() && !$this->_end_date) {
+ if (!$this->isFee() && !$this->_end_date) {
unset($values['date_fin_cotis']);
}
- $success = false;
if (!isset($this->_id) || $this->_id == '') {
//we're inserting a new contribution
unset($values[self::PK]);
_T("Contribution added"),
Adherent::getSName($this->zdb, $this->_member)
);
- $success = true;
- $event = 'contribution.add';
+ $event = $this->getAddEventName();
} else {
$hist->add(_T("Fail to add new contribution."));
throw new \Exception(
} else {
//we're editing an existing contribution
$update = $this->zdb->update(self::TABLE);
- $update->set($values)->where(
- self::PK . '=' . $this->_id
- );
+ $update->set($values)->where([self::PK => $this->_id]);
$edit = $this->zdb->execute($update);
//edit == 0 does not mean there were an error, but that there
);
}
- if ($edit === false) {
- throw new \Exception(
- 'An error occurred updating contribution # ' . $this->_id . '!'
- );
- }
- $success = true;
- $event = 'contribution.edit';
+ $event = $this->getEditEventName();
}
//update deadline
- if ($this->isCotis()) {
- $deadline = $this->updateDeadline();
- if ($deadline !== true) {
- //if something went wrong, we rollback transaction
- throw new \Exception('An error occurred updating member\'s deadline');
- }
+ if ($this->isFee()) {
+ $this->updateDeadline();
}
//dynamic fields
- if ($success) {
- $success = $this->dynamicsStore(true);
- }
+ $this->dynamicsStore(true);
$this->zdb->connection->commit();
$this->_orig_amount = $this->_amount;
//send event at the end of process, once all has been stored
- if ($event !== null) {
- $emitter->emit($event, $this);
+ if ($event !== null && $this->areEventsEnabled()) {
+ $emitter->dispatch(new GaletteEvent($event, $this));
}
return true;
} catch (Throwable $e) {
- $this->zdb->connection->rollBack();
- Analog::log(
- 'Something went wrong :\'( | ' . $e->getMessage() . "\n" .
- $e->getTraceAsString(),
- Analog::ERROR
- );
- return false;
+ if ($this->zdb->connection->inTransaction()) {
+ $this->zdb->connection->rollBack();
+ }
+ throw $e;
}
}
$due_date = self::getDueDate($this->zdb, $this->_member);
if ($due_date != '') {
- $date_fin_update = $due_date;
+ $due_date_update = $due_date;
} else {
- $date_fin_update = new Expression('NULL');
+ $due_date_update = new Expression('NULL');
}
$update = $this->zdb->update(Adherent::TABLE);
$update->set(
- array('date_echeance' => $date_fin_update)
+ array('date_echeance' => $due_date_update)
)->where(
- Adherent::PK . '=' . $this->_member
+ [Adherent::PK => $this->_member]
);
$this->zdb->execute($update);
return true;
$e->getMessage(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
}
$delete = $this->zdb->delete(self::TABLE);
- $delete->where(self::PK . ' = ' . $this->_id);
+ $delete->where([self::PK => $this->_id]);
$del = $this->zdb->execute($delete);
if ($del->count() > 0) {
$this->updateDeadline();
$this->dynamicsRemove(true);
} else {
- throw new \RuntimeException(
- 'Contribution has not been removed!'
+ Analog::log(
+ 'Contribution has not been removed!',
+ Analog::WARNING
);
+ return false;
}
if ($transaction) {
$this->zdb->connection->commit();
}
- $emitter->emit('contribution.remove', $this);
+ $emitter->dispatch(new GaletteEvent('contribution.remove', $this));
return true;
} catch (Throwable $e) {
if ($transaction) {
$this->_id . ' | ' . $e->getMessage(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
public function getFieldLabel($field)
{
$label = $this->_fields[$field]['label'];
- if ($this->isCotis() && $field == 'date_debut_cotis') {
+ if ($this->isFee() && $field == 'date_debut_cotis') {
$label = $this->_fields[$field]['cotlabel'];
}
//replace " "
* @param Db $zdb Database instance
* @param integer $member_id Member identifier
*
- * @return date
+ * @return string
*/
public static function getDueDate(Db $zdb, $member_id)
{
'c.' . ContributionsTypes::PK . '=ct.' . ContributionsTypes::PK,
array()
)->where(
- Adherent::PK . ' = ' . $member_id
+ [Adherent::PK => $member_id]
)->where(
array('cotis_extension' => new Expression('true'))
);
'An error occurred trying to retrieve member\'s due date',
Analog::ERROR
);
- return false;
+ throw $e;
}
}
$update->set(
array(Transaction::PK => null)
)->where(
- self::PK . ' = ' . $contrib_id
+ [self::PK => $contrib_id]
);
$zdb->execute($update);
return true;
' to transaction #' . $trans_id . ' | ' . $e->getMessage(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
$update = $zdb->update(self::TABLE);
$update->set(
array(Transaction::PK => $trans_id)
- )->where(self::PK . ' = ' . $contrib_id);
+ )->where([self::PK => $contrib_id]);
$zdb->execute($update);
return true;
' to transaction #' . $trans_id . ' | ' . $e->getMessage(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
/**
- * Is current contribution a cotisation
+ * Is current contribution a membership fee
*
* @return boolean
*/
- public function isCotis()
+ public function isFee()
{
return $this->_is_cotis;
}
*/
public function getRawType()
{
- if ($this->isCotis()) {
+ if ($this->isFee()) {
return 'membership';
} else {
return 'donation';
*/
public function getTypeLabel()
{
- if ($this->isCotis()) {
+ if ($this->isFee()) {
return _T("Membership");
} else {
return _T("Donation");
/**
* Get payment type label
*
+ * @param boolean $translated Whether to translate
+ *
* @return string
*/
- public function getPaymentType()
+ public function getPaymentType(bool $translated = false): string
{
if ($this->_payment_type === null) {
return '-';
}
$ptype = new PaymentType($this->zdb, (int)$this->payment_type);
- return $ptype->getName(false);
+ return $ptype->getName($translated);
}
/**
* Global getter method
*
- * @param string $name name of the property we want to retrive
+ * @param string $name name of the property we want to retrieve
*
- * @return false|object the called property
+ * @return mixed the called property
*/
public function __get($name)
{
switch ($name) {
case 'is_cotis':
- return $this->isCotis();
- break;
+ return $this->isFee();
default:
throw new \RuntimeException("Call to __get for '$name' is forbidden!");
}
case 'raw_begin_date':
case 'raw_end_date':
$rname = '_' . substr($name, 4);
- if ($this->$rname != '') {
+ if ($this->$rname !== null && $this->$rname != '') {
try {
$d = new \DateTime($this->$rname);
return $d;
case 'date':
case 'begin_date':
case 'end_date':
- if ($this->$rname != '') {
+ if ($this->$rname !== null && $this->$rname != '') {
try {
$d = new \DateTime($this->$rname);
return $d->format(__("Y-m-d"));
break;
case 'duration':
if ($this->_is_cotis) {
- $date_end = new \DateTime($this->_end_date);
- $date_start = new \DateTime($this->_begin_date);
- $diff = $date_end->diff($date_start);
- return $diff->format('%y') * 12 + $diff->format('%m');
+ // Caution : the end_date stored is actually the due date.
+ // Adding a day to compute the next_begin_date is required
+ // to return the right number of months.
+ $next_begin_date = new \DateTime($this->_end_date ?? $this->_begin_date);
+ $next_begin_date->add(new \DateInterval('P1D'));
+ $begin_date = new \DateTime($this->_begin_date);
+ $diff = $next_begin_date->diff($begin_date);
+ return (int)$diff->format('%y') * 12 + (int)$diff->format('%m');
} else {
return '';
}
- break;
case 'spayment_type':
- if ($this->_payment_type === null) {
- return '-';
- }
-
- $ptype = new PaymentType($this->zdb, (int)$this->payment_type);
- return $ptype->getName();
-
- break;
+ return $this->getPaymentType(true);
case 'model':
if ($this->_is_cotis === null) {
return null;
}
- return ($this->isCotis()) ?
+ return ($this->isFee()) ?
PdfModel::INVOICE_MODEL : PdfModel::RECEIPT_MODEL;
- break;
default:
return $this->$rname;
- break;
}
} else {
Analog::log(
}
}
+ /**
+ * Global isset method
+ * Required for twig to access properties via __get
+ *
+ * @param string $name name of the property we want to retrieve
+ *
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ $forbidden = array('is_cotis');
+ $virtuals = array('duration', 'spayment_type', 'model', 'raw_date',
+ 'raw_begin_date', 'raw_end_date'
+ );
+
+ $rname = '_' . $name;
+
+ if (in_array($name, $forbidden)) {
+ switch ($name) {
+ case 'is_cotis':
+ return true;
+ }
+ } elseif (
+ property_exists($this, $rname)
+ || in_array($name, $virtuals)
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+
/**
* Global setter method
*
* @param string $name name of the property we want to assign a value to
- * @param object $value a relevant value for the property
+ * @param mixed $value a relevant value for the property
*
* @return void
*/
*
* @return Contribution
*/
- public function setSendmail($send = true)
+ public function setSendmail(bool $send = true)
{
$this->sendmail = $send;
return $this;
{
return $this->sendmail;
}
+
+ /**
+ * Handle files (dynamics files)
+ *
+ * @param array $files Files sent
+ *
+ * @return array|true
+ */
+ public function handleFiles($files)
+ {
+ $this->errors = [];
+
+ $this->dynamicsFiles($files);
+
+ if (count($this->errors) > 0) {
+ Analog::log(
+ 'Some errors has been threw attempting to edit/store a contribution files' . "\n" .
+ print_r($this->errors, true),
+ Analog::ERROR
+ );
+ return $this->errors;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Get required fields list
+ *
+ * @return array
+ */
+ public function getRequired(): array
+ {
+ return [
+ 'id_type_cotis' => 1,
+ 'id_adh' => 1,
+ 'date_enreg' => 1,
+ 'date_debut_cotis' => 1,
+ 'date_fin_cotis' => $this->isFee() ? 1 : 0,
+ 'montant_cotis' => $this->isFee() ? 1 : 0
+ ];
+ }
+
+ /**
+ * Can current logged-in user display contribution
+ *
+ * @param Login $login Login instance
+ *
+ * @return boolean
+ */
+ public function canShow(Login $login): bool
+ {
+ //non-logged-in members cannot show contributions
+ if (!$login->isLogged()) {
+ return false;
+ }
+
+ //admin and staff users can edit, as well as member itself
+ if (!$this->id || $login->id == $this->_member || $login->isAdmin() || $login->isStaff()) {
+ return true;
+ }
+
+ //parent can see their children contributions
+ $parent = new Adherent($this->zdb);
+ $parent
+ ->disableAllDeps()
+ ->enableDep('children')
+ ->load($this->login->id);
+ if ($parent->hasChildren()) {
+ foreach ($parent->children as $child) {
+ if ($child->id === $this->_member) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get prefix for events
+ *
+ * @return string
+ */
+ protected function getEventsPrefix(): string
+ {
+ return 'contribution';
+ }
}